From a47f0f375d16596f935614f878fcca309b0d9e73 Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Mon, 17 Jun 2019 12:38:05 +0200 Subject: [PATCH 01/10] chore: removed unused obsolete methods, fixed some tests that still relied on these methods --- .../JsonApiDeserializer_Benchmarks.cs | 3 +-- .../Controllers/TodoCollectionsController.cs | 2 +- .../Configuration/JsonApiOptions.cs | 6 ----- .../Data/DbContextResolver.cs | 4 ++-- .../Data/DefaultEntityRepository.cs | 4 ++-- .../Data/IDbContextResolver.cs | 3 +++ .../Extensions/IQueryableExtensions.cs | 9 -------- .../Extensions/ModelStateExtensions.cs | 20 ----------------- .../Internal/ContextGraph.cs | 15 ------------- src/JsonApiDotNetCore/Internal/Error.cs | 22 +------------------ .../Internal/JsonApiException.cs | 12 +--------- .../Internal/Query/AttrFilterQuery.cs | 5 ----- .../Internal/Query/FilterQuery.cs | 3 --- .../Internal/Query/RelatedAttrFilterQuery.cs | 10 +-------- .../Internal/Query/SortQuery.cs | 7 ------ src/JsonApiDotNetCore/Models/Identifiable.cs | 6 ----- .../Serialization/JsonApiDeSerializer.cs | 10 --------- .../Services/IJsonApiContext.cs | 6 ----- .../Services/JsonApiContext.cs | 4 ---- .../ServiceDiscoveryFacadeTests.cs | 14 ++++++++++-- .../Data/DefaultEntityRepository_Tests.cs | 9 ++++---- .../ResourceHooks/ResourceHooksTestsSetup.cs | 1 - 22 files changed, 29 insertions(+), 146 deletions(-) delete mode 100644 src/JsonApiDotNetCore/Internal/ContextGraph.cs diff --git a/benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs b/benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs index d65f0e65c1..983bc07f90 100644 --- a/benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs +++ b/benchmarks/Serialization/JsonApiDeserializer_Benchmarks.cs @@ -45,9 +45,8 @@ public JsonApiDeserializer_Benchmarks() { jsonApiOptions.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); jsonApiContextMock.Setup(m => m.Options).Returns(jsonApiOptions); - var genericProcessorFactoryMock = new Mock(); - _jsonApiDeSerializer = new JsonApiDeSerializer(jsonApiContextMock.Object, genericProcessorFactoryMock.Object); + _jsonApiDeSerializer = new JsonApiDeSerializer(jsonApiContextMock.Object); } [Benchmark] diff --git a/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoCollectionsController.cs b/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoCollectionsController.cs index 6bac2ff6a0..6a27038191 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoCollectionsController.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Controllers/TodoCollectionsController.cs @@ -33,7 +33,7 @@ public override async Task PatchAsync(Guid id, [FromBody] TodoIte if (entity.Name == "PRE-ATTACH-TEST") { var targetTodoId = entity.TodoItems.First().Id; - var todoItemContext = _dbResolver.GetDbSet(); + var todoItemContext = _dbResolver.GetContext().Set(); await todoItemContext.Where(ti => ti.Id == targetTodoId).FirstOrDefaultAsync(); } return await base.PatchAsync(id, entity); diff --git a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs index 906ee4fba8..21efdb97ed 100644 --- a/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs +++ b/src/JsonApiDotNetCore/Configuration/JsonApiOptions.cs @@ -181,12 +181,6 @@ public class JsonApiOptions /// public bool ValidateModelState { get; set; } - [Obsolete("JsonContract resolver can now be set on SerializerSettings.")] - public IContractResolver JsonContractResolver - { - get => SerializerSettings.ContractResolver; - set => SerializerSettings.ContractResolver = value; - } public JsonSerializerSettings SerializerSettings { get; } = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore, diff --git a/src/JsonApiDotNetCore/Data/DbContextResolver.cs b/src/JsonApiDotNetCore/Data/DbContextResolver.cs index e681e660bb..7ce7eec921 100644 --- a/src/JsonApiDotNetCore/Data/DbContextResolver.cs +++ b/src/JsonApiDotNetCore/Data/DbContextResolver.cs @@ -15,7 +15,7 @@ public DbContextResolver(TContext context) public DbContext GetContext() => _context; - public DbSet GetDbSet() where TEntity : class - => _context.GetDbSet(); + public DbSet GetDbSet() where TEntity : class => null; + } } diff --git a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs index dabf447efe..646371840b 100644 --- a/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs +++ b/src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs @@ -56,7 +56,7 @@ public DefaultEntityRepository( ResourceDefinition resourceDefinition = null) { _context = contextResolver.GetContext(); - _dbSet = contextResolver.GetDbSet(); + _dbSet = _context.Set(); _jsonApiContext = jsonApiContext; _genericProcessorFactory = _jsonApiContext.GenericProcessorFactory; _resourceDefinition = resourceDefinition; @@ -69,7 +69,7 @@ public DefaultEntityRepository( ResourceDefinition resourceDefinition = null) { _context = contextResolver.GetContext(); - _dbSet = contextResolver.GetDbSet(); + _dbSet = _context.Set(); _jsonApiContext = jsonApiContext; _logger = loggerFactory.CreateLogger>(); _genericProcessorFactory = _jsonApiContext.GenericProcessorFactory; diff --git a/src/JsonApiDotNetCore/Data/IDbContextResolver.cs b/src/JsonApiDotNetCore/Data/IDbContextResolver.cs index 5a8c5a2e12..4915d788c4 100644 --- a/src/JsonApiDotNetCore/Data/IDbContextResolver.cs +++ b/src/JsonApiDotNetCore/Data/IDbContextResolver.cs @@ -1,3 +1,4 @@ +using System; using Microsoft.EntityFrameworkCore; namespace JsonApiDotNetCore.Data @@ -5,6 +6,8 @@ namespace JsonApiDotNetCore.Data public interface IDbContextResolver { DbContext GetContext(); + + [Obsolete("Use DbContext.Set() instead", error: true)] DbSet GetDbSet() where TEntity : class; } diff --git a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs index 8407ede0d3..87de9d187d 100644 --- a/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/IQueryableExtensions.cs @@ -30,15 +30,6 @@ private static MethodInfo ContainsMethod } } - [Obsolete("Use overload Sort(IJsonApiContext, List) instead.", error: true)] - public static IQueryable Sort(this IQueryable source, List sortQueries) => null; - - [Obsolete("Use overload Sort(IJsonApiContext, SortQuery) instead.", error: true)] - public static IOrderedQueryable Sort(this IQueryable source, SortQuery sortQuery) => null; - - [Obsolete("Use overload Sort(IJsonApiContext, SortQuery) instead.", error: true)] - public static IOrderedQueryable Sort(this IOrderedQueryable source, SortQuery sortQuery) => null; - public static IQueryable Sort(this IQueryable source, IJsonApiContext jsonApiContext, List sortQueries) { if (sortQueries == null || sortQueries.Count == 0) diff --git a/src/JsonApiDotNetCore/Extensions/ModelStateExtensions.cs b/src/JsonApiDotNetCore/Extensions/ModelStateExtensions.cs index 4b31a7f021..023ef09ae2 100644 --- a/src/JsonApiDotNetCore/Extensions/ModelStateExtensions.cs +++ b/src/JsonApiDotNetCore/Extensions/ModelStateExtensions.cs @@ -7,26 +7,6 @@ namespace JsonApiDotNetCore.Extensions { public static class ModelStateExtensions { - [Obsolete("Use Generic Method ConvertToErrorCollection(IResourceGraph resourceGraph) instead for full validation errors")] - public static ErrorCollection ConvertToErrorCollection(this ModelStateDictionary modelState) - { - ErrorCollection collection = new ErrorCollection(); - foreach (var entry in modelState) - { - if (entry.Value.Errors.Any() == false) - continue; - - foreach (var modelError in entry.Value.Errors) - { - if (modelError.Exception is JsonApiException jex) - collection.Errors.AddRange(jex.GetError().Errors); - else - collection.Errors.Add(new Error(400, entry.Key, modelError.ErrorMessage, modelError.Exception != null ? ErrorMeta.FromException(modelError.Exception) : null)); - } - } - - return collection; - } public static ErrorCollection ConvertToErrorCollection(this ModelStateDictionary modelState, IResourceGraph resourceGraph) { ErrorCollection collection = new ErrorCollection(); diff --git a/src/JsonApiDotNetCore/Internal/ContextGraph.cs b/src/JsonApiDotNetCore/Internal/ContextGraph.cs deleted file mode 100644 index 18aab6646e..0000000000 --- a/src/JsonApiDotNetCore/Internal/ContextGraph.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using JsonApiDotNetCore.Models; - -namespace JsonApiDotNetCore.Internal -{ - /// - [Obsolete("Use IResourceGraph instead.")] - public interface IContextGraph : IResourceGraph { } - - [Obsolete("Use ResourceGraph instead.")] - public class ContextGraph : ResourceGraph { } -} diff --git a/src/JsonApiDotNetCore/Internal/Error.cs b/src/JsonApiDotNetCore/Internal/Error.cs index 7e45f65be3..058fdf6f36 100644 --- a/src/JsonApiDotNetCore/Internal/Error.cs +++ b/src/JsonApiDotNetCore/Internal/Error.cs @@ -9,17 +9,7 @@ namespace JsonApiDotNetCore.Internal { public class Error { - public Error() - { } - - [Obsolete("Use Error constructors with int typed status")] - public Error(string status, string title, ErrorMeta meta = null, object source = null) - { - Status = status; - Title = title; - Meta = meta; - Source = source; - } + public Error() { } public Error(int status, string title, ErrorMeta meta = null, object source = null) { @@ -29,16 +19,6 @@ public Error(int status, string title, ErrorMeta meta = null, object source = nu Source = source; } - [Obsolete("Use Error constructors with int typed status")] - public Error(string status, string title, string detail, ErrorMeta meta = null, object source = null) - { - Status = status; - Title = title; - Detail = detail; - Meta = meta; - Source = source; - } - public Error(int status, string title, string detail, ErrorMeta meta = null, object source = null) { Status = status.ToString(); diff --git a/src/JsonApiDotNetCore/Internal/JsonApiException.cs b/src/JsonApiDotNetCore/Internal/JsonApiException.cs index 0852ac1e04..0f1f06dfdb 100644 --- a/src/JsonApiDotNetCore/Internal/JsonApiException.cs +++ b/src/JsonApiDotNetCore/Internal/JsonApiException.cs @@ -14,17 +14,7 @@ public JsonApiException(ErrorCollection errorCollection) public JsonApiException(Error error) : base(error.Title) => _errors.Add(error); - - [Obsolete("Use int statusCode overload instead")] - public JsonApiException(string statusCode, string message, string source = null) - : base(message) - => _errors.Add(new Error(statusCode, message, null, GetMeta(), source)); - - [Obsolete("Use int statusCode overload instead")] - public JsonApiException(string statusCode, string message, string detail, string source = null) - : base(message) - => _errors.Add(new Error(statusCode, message, detail, GetMeta(), source)); - + public JsonApiException(int statusCode, string message, string source = null) : base(message) => _errors.Add(new Error(statusCode, message, null, GetMeta(), source)); diff --git a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs index 92e79a85ee..3205e1e01a 100644 --- a/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/AttrFilterQuery.cs @@ -16,11 +16,6 @@ public AttrFilterQuery( if (Attribute.IsFilterable == false) throw new JsonApiException(400, $"Filter is not allowed for attribute '{Attribute.PublicAttributeName}'."); - - FilteredAttribute = Attribute; } - - [Obsolete("Use " + nameof(BaseAttrQuery.Attribute) + " instead.")] - public AttrAttribute FilteredAttribute { get; set; } } } diff --git a/src/JsonApiDotNetCore/Internal/Query/FilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/FilterQuery.cs index 541203dc4c..e1b53cd47d 100644 --- a/src/JsonApiDotNetCore/Internal/Query/FilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/FilterQuery.cs @@ -20,13 +20,10 @@ public class FilterQuery : BaseQuery public FilterQuery(string attribute, string value, string operation) : base(attribute) { - Key = attribute.ToProperCase(); Value = value; Operation = operation; } - [Obsolete("Key has been replaced by '" + nameof(Attribute) + "'. Members should be located by their public name, not by coercing the provided value to the internal name.")] - public string Key { get; set; } public string Value { get; set; } public string Operation { get; set; } diff --git a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs index 96d33d0e72..8fef8de693 100644 --- a/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/RelatedAttrFilterQuery.cs @@ -19,15 +19,7 @@ public RelatedAttrFilterQuery( if (Attribute.IsFilterable == false) throw new JsonApiException(400, $"Filter is not allowed for attribute '{Attribute.PublicAttributeName}'."); - - FilteredRelationship = Relationship; - FilteredAttribute = Attribute; + } - - [Obsolete("Use " + nameof(Attribute) + " instead.")] - public AttrAttribute FilteredAttribute { get; set; } - - [Obsolete("Use " + nameof(Relationship) + " instead.")] - public RelationshipAttribute FilteredRelationship { get; set; } } } diff --git a/src/JsonApiDotNetCore/Internal/Query/SortQuery.cs b/src/JsonApiDotNetCore/Internal/Query/SortQuery.cs index 254d328a43..7194b6e948 100644 --- a/src/JsonApiDotNetCore/Internal/Query/SortQuery.cs +++ b/src/JsonApiDotNetCore/Internal/Query/SortQuery.cs @@ -8,10 +8,6 @@ namespace JsonApiDotNetCore.Internal.Query /// public class SortQuery : BaseQuery { - [Obsolete("Use constructor overload (SortDirection, string) instead. The string should be the publicly exposed attribute name.", error: true)] - public SortQuery(SortDirection direction, AttrAttribute sortedAttribute) - : base(sortedAttribute.PublicAttributeName) { } - public SortQuery(SortDirection direction, string attribute) : base(attribute) { @@ -22,8 +18,5 @@ public SortQuery(SortDirection direction, string attribute) /// Direction the sort should be applied /// public SortDirection Direction { get; set; } - - [Obsolete("Use string based Attribute instead.", error: true)] - public AttrAttribute SortedAttribute { get; set; } } } diff --git a/src/JsonApiDotNetCore/Models/Identifiable.cs b/src/JsonApiDotNetCore/Models/Identifiable.cs index 663786de93..b62f31fe89 100644 --- a/src/JsonApiDotNetCore/Models/Identifiable.cs +++ b/src/JsonApiDotNetCore/Models/Identifiable.cs @@ -62,11 +62,5 @@ protected virtual T GetTypedId(string value) var convertedValue = TypeHelper.ConvertType(value, typeof(T)); return convertedValue == null ? default : (T)convertedValue; } - - [Obsolete("Use GetTypedId instead")] - protected virtual object GetConcreteId(string value) - { - return TypeHelper.ConvertType(value, typeof(T)); - } } } diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index df36966b36..6906a4470f 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -18,16 +18,6 @@ public class JsonApiDeSerializer : IJsonApiDeSerializer { private readonly IJsonApiContext _jsonApiContext; - [Obsolete( - "The deserializer no longer depends on the IGenericProcessorFactory", - error: false)] - public JsonApiDeSerializer( - IJsonApiContext jsonApiContext, - IGenericProcessorFactory genericProcessorFactory) - { - _jsonApiContext = jsonApiContext; - } - public JsonApiDeSerializer(IJsonApiContext jsonApiContext) { _jsonApiContext = jsonApiContext; diff --git a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs index e0a14a4e02..d3fb014bcc 100644 --- a/src/JsonApiDotNetCore/Services/IJsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/IJsonApiContext.cs @@ -139,9 +139,6 @@ public interface IJsonApiRequest : IJsonApiApplication, IUpdateRequest, IQueryRe /// If the request is on the `{id}/relationships/{relationshipName}` route /// bool IsRelationshipPath { get; } - - [Obsolete("Use `IsRelationshipPath` instead.")] - bool IsRelationshipData { get; set; } } public interface IJsonApiContext : IJsonApiRequest @@ -150,9 +147,6 @@ public interface IJsonApiContext : IJsonApiRequest IMetaBuilder MetaBuilder { get; set; } IGenericProcessorFactory GenericProcessorFactory { get; set; } - [Obsolete("Use the proxied method IControllerContext.GetControllerAttribute instead.")] - TAttribute GetControllerAttribute() where TAttribute : Attribute; - /// /// **_Experimental_**: do not use. It is likely to change in the future. /// diff --git a/src/JsonApiDotNetCore/Services/JsonApiContext.cs b/src/JsonApiDotNetCore/Services/JsonApiContext.cs index bec78e8237..495354b1e0 100644 --- a/src/JsonApiDotNetCore/Services/JsonApiContext.cs +++ b/src/JsonApiDotNetCore/Services/JsonApiContext.cs @@ -139,10 +139,6 @@ private PageManager GetPageManager() }; } - [Obsolete("Use the proxied method IControllerContext.GetControllerAttribute instead.")] - public TAttribute GetControllerAttribute() where TAttribute : Attribute - => _controllerContext.GetControllerAttribute(); - public void BeginOperation() { IncludedRelationships = new List(); diff --git a/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs b/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs index 6953b5f49c..09ffcfcfc1 100644 --- a/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs +++ b/test/DiscoveryTests/ServiceDiscoveryFacadeTests.cs @@ -5,6 +5,7 @@ using JsonApiDotNetCore.Graph; using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Services; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Moq; using Xunit; @@ -14,7 +15,16 @@ namespace DiscoveryTests public class ServiceDiscoveryFacadeTests { private readonly IServiceCollection _services = new ServiceCollection(); - private readonly ResourceGraphBuilder _graphBuilder = new ResourceGraphBuilder(); + private readonly ResourceGraphBuilder _graphBuilder = new ResourceGraphBuilder(); + + public ServiceDiscoveryFacadeTests() + { + var contextMock = new Mock(); + var dbResolverMock = new Mock(); + dbResolverMock.Setup(m => m.GetContext()).Returns(new Mock().Object); + TestModelRepository._dbContextResolver = dbResolverMock.Object; + } + private ServiceDiscoveryFacade _facade => new ServiceDiscoveryFacade(_services, _graphBuilder); [Fact] @@ -79,7 +89,7 @@ public TestModelService() : base(_jsonApiContext, _repo) { } public class TestModelRepository : DefaultEntityRepository { - private static IDbContextResolver _dbContextResolver = new Mock().Object; + internal static IDbContextResolver _dbContextResolver; private static IJsonApiContext _jsonApiContext = new Mock().Object; public TestModelRepository() : base(_jsonApiContext, _dbContextResolver) { } } diff --git a/test/UnitTests/Data/DefaultEntityRepository_Tests.cs b/test/UnitTests/Data/DefaultEntityRepository_Tests.cs index 958639575e..14116bb574 100644 --- a/test/UnitTests/Data/DefaultEntityRepository_Tests.cs +++ b/test/UnitTests/Data/DefaultEntityRepository_Tests.cs @@ -77,14 +77,15 @@ public async Task UpdateAsync_Updates_Attributes_In_AttributesToUpdate() private DefaultEntityRepository GetRepository() { + + _contextMock + .Setup(m => m.Set()) + .Returns(_dbSetMock.Object); + _contextResolverMock .Setup(m => m.GetContext()) .Returns(_contextMock.Object); - _contextResolverMock - .Setup(m => m.GetDbSet()) - .Returns(_dbSetMock.Object); - _jsonApiContextMock .Setup(m => m.AttributesToUpdate) .Returns(_attrsToUpdate); diff --git a/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs b/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs index 271e1baf09..02b473b448 100644 --- a/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs +++ b/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs @@ -343,7 +343,6 @@ IDbContextResolver CreateTestDbResolver(AppDbContext dbContext) where TM { var mock = new Mock(); mock.Setup(r => r.GetContext()).Returns(dbContext); - mock.Setup(r => r.GetDbSet()).Returns(dbContext.Set()); return mock.Object; } From 46f50e15e403d535fb1f284e23477d358cff3c1b Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 20 Jun 2019 08:09:01 +0200 Subject: [PATCH 02/10] feat: made internal constructors public, removed usage RelationshipProxy when RelationshipAttribute suffices --- .../Hooks/Execution/AffectedRelationships.cs | 8 ++--- .../Hooks/Execution/AffectedResourceDiff.cs | 4 +-- .../Hooks/Execution/AffectedResources.cs | 2 +- .../Hooks/Execution/HookExecutorHelper.cs | 22 +++++++------- .../Hooks/Execution/IHookExecutorHelper.cs | 4 +-- .../Hooks/ResourceHookExecutor.cs | 29 ++++++++++--------- .../RelationshipsFromPreviousLayer.cs | 12 ++++---- .../Hooks/Traversal/RootNode.cs | 8 ++--- .../Internal/ResourceGraph.cs | 5 ++++ 9 files changed, 50 insertions(+), 44 deletions(-) diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs index dc2590f9bd..e37195ea5e 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs @@ -30,13 +30,13 @@ public interface IAffectedRelationships : IAffectedRelationships whe public class AffectedRelationships : IAffectedRelationships where TDependent : class, IIdentifiable { - private readonly Dictionary> _groups; + private readonly Dictionary> _groups; public Dictionary> AllByRelationships() { - return _groups?.ToDictionary(p => p.Key.Attribute, p => p.Value); + return _groups; } - internal AffectedRelationships(Dictionary relationships) + public AffectedRelationships(Dictionary relationships) { _groups = relationships.ToDictionary(kvp => kvp.Key, kvp => new HashSet((IEnumerable)kvp.Value)); } @@ -48,7 +48,7 @@ public Dictionary> GetByRelationship< public Dictionary> GetByRelationship(Type principalType) { - return _groups?.Where(p => p.Key.PrincipalType == principalType).ToDictionary(p => p.Key.Attribute, p => p.Value); + return _groups?.Where(p => p.Key.PrincipalType == principalType).ToDictionary(p => p.Key, p => p.Value); } } } diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs index 59102a50ad..bac7702ebc 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs @@ -31,9 +31,9 @@ public class ResourceDiff : AffectedResources, IAffectedResou /// public HashSet DatabaseValues { get => _databaseValues ?? ThrowNoDbValuesError(); } - internal ResourceDiff(IEnumerable requestEntities, + public ResourceDiff(IEnumerable requestEntities, IEnumerable databaseEntities, - Dictionary relationships) : base(requestEntities, relationships) + Dictionary relationships) : base(requestEntities, relationships) { _databaseValues = (HashSet)databaseEntities; _databaseValuesLoaded |= _databaseValues != null; diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs index a004dcc244..6151f10314 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs @@ -19,7 +19,7 @@ public class AffectedResources : AffectedRelationships, IAffec public HashSet Entities { get; } internal AffectedResources(IEnumerable entities, - Dictionary relationships) : base(relationships) + Dictionary relationships) : base(relationships) { Entities = new HashSet(entities.Cast()); } diff --git a/src/JsonApiDotNetCore/Hooks/Execution/HookExecutorHelper.cs b/src/JsonApiDotNetCore/Hooks/Execution/HookExecutorHelper.cs index 68b8018c01..99e9ce23b1 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/HookExecutorHelper.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/HookExecutorHelper.cs @@ -24,7 +24,6 @@ internal class HookExecutorHelper : IHookExecutorHelper protected readonly Dictionary _hookDiscoveries; protected readonly List _targetedHooksForRelatedEntities; protected readonly IJsonApiContext _context; - protected Dictionary> _meta; public HookExecutorHelper( IGenericProcessorFactory genericProcessorFactory, @@ -35,7 +34,6 @@ IJsonApiContext context _genericProcessorFactory = genericProcessorFactory; _graph = graph; _context = context; - _meta = new Dictionary>(); _hookContainers = new Dictionary(); _hookDiscoveries = new Dictionary(); _targetedHooksForRelatedEntities = new List(); @@ -81,9 +79,9 @@ public IResourceHookContainer GetResourceHookContainer(Resourc return (IResourceHookContainer)GetResourceHookContainer(typeof(TEntity), hook); } - public IEnumerable LoadDbValues(PrincipalType entityTypeForRepository, IEnumerable entities, ResourceHook hook, params RelationshipProxy[] relationships) + public IEnumerable LoadDbValues(PrincipalType entityTypeForRepository, IEnumerable entities, ResourceHook hook, params RelationshipAttribute[] relationships) { - var paths = relationships.Select(p => p.Attribute.RelationshipPath).ToArray(); + var paths = relationships.Select(p => p.RelationshipPath).ToArray(); var idType = GetIdentifierType(entityTypeForRepository); var parameterizedGetWhere = GetType() .GetMethod(nameof(GetWhereAndInclude), BindingFlags.NonPublic | BindingFlags.Instance) @@ -95,7 +93,7 @@ public IEnumerable LoadDbValues(PrincipalType entityTypeForRepository, IEnumerab return (IEnumerable)Activator.CreateInstance(typeof(HashSet<>).MakeGenericType(entityTypeForRepository), values.Cast(entityTypeForRepository)); } - public HashSet LoadDbValues(IEnumerable entities, ResourceHook hook, params RelationshipProxy[] relationships) where TEntity : class, IIdentifiable + public HashSet LoadDbValues(IEnumerable entities, ResourceHook hook, params RelationshipAttribute[] relationships) where TEntity : class, IIdentifiable { var entityType = typeof(TEntity); var dbValues = LoadDbValues(entityType, entities, hook, relationships)?.Cast(); @@ -168,11 +166,11 @@ IEntityReadRepository GetRepository() where TEntity } - public Dictionary LoadImplicitlyAffected( - Dictionary principalEntitiesByRelation, + public Dictionary LoadImplicitlyAffected( + Dictionary principalEntitiesByRelation, IEnumerable existingDependentEntities = null) { - var implicitlyAffected = new Dictionary(); + var implicitlyAffected = new Dictionary(); foreach (var kvp in principalEntitiesByRelation) { if (IsHasManyThrough(kvp, out var principals, out var relationship)) continue; @@ -212,13 +210,13 @@ public Dictionary LoadImplicitlyAffected( } - bool IsHasManyThrough(KeyValuePair kvp, + bool IsHasManyThrough(KeyValuePair kvp, out IEnumerable entities, - out RelationshipProxy proxy) + out RelationshipAttribute attr) { - proxy = kvp.Key; + attr = kvp.Key; entities = (kvp.Value); - return (kvp.Key.Attribute is HasManyThroughAttribute); + return (kvp.Key is HasManyThroughAttribute); } } } \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Hooks/Execution/IHookExecutorHelper.cs b/src/JsonApiDotNetCore/Hooks/Execution/IHookExecutorHelper.cs index 33546aa864..63b3621a34 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/IHookExecutorHelper.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/IHookExecutorHelper.cs @@ -37,12 +37,12 @@ internal interface IHookExecutorHelper /// Load the implicitly affected entities from the database for a given set of target target entities and involved relationships /// /// The implicitly affected entities by relationship - Dictionary LoadImplicitlyAffected(Dictionary principalEntities, IEnumerable existingDependentEntities = null); + Dictionary LoadImplicitlyAffected(Dictionary principalEntities, IEnumerable existingDependentEntities = null); /// /// For a set of entities, loads current values from the database /// - IEnumerable LoadDbValues(Type repositoryEntityType, IEnumerable entities, ResourceHook hook, params RelationshipProxy[] relationships); + IEnumerable LoadDbValues(Type repositoryEntityType, IEnumerable entities, ResourceHook hook, params RelationshipAttribute[] relationships); bool ShouldLoadDbValues(Type containerEntityType, ResourceHook hook); } } \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs b/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs index aca190225a..154eada525 100644 --- a/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs +++ b/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs @@ -47,7 +47,8 @@ public virtual IEnumerable BeforeUpdate(IEnumerable e { if (GetHook(ResourceHook.BeforeUpdate, entities, out var container, out var node)) { - var dbValues = LoadDbValues(typeof(TEntity), (IEnumerable)node.UniqueEntities, ResourceHook.BeforeUpdate, node.RelationshipsToNextLayer); + var relationships = node.RelationshipsToNextLayer.Select(p => p.Attribute).ToArray(); + var dbValues = LoadDbValues(typeof(TEntity), (IEnumerable)node.UniqueEntities, ResourceHook.BeforeUpdate, relationships); var diff = new ResourceDiff(node.UniqueEntities, dbValues, node.PrincipalsToNextLayer()); IEnumerable updated = container.BeforeUpdate(diff, pipeline); node.UpdateUnique(updated); @@ -79,7 +80,8 @@ public virtual IEnumerable BeforeDelete(IEnumerable e { if (GetHook(ResourceHook.BeforeDelete, entities, out var container, out var node)) { - var targetEntities = LoadDbValues(typeof(TEntity), (IEnumerable)node.UniqueEntities, ResourceHook.BeforeDelete, node.RelationshipsToNextLayer) ?? node.UniqueEntities; + var relationships = node.RelationshipsToNextLayer.Select(p => p.Attribute).ToArray(); + var targetEntities = LoadDbValues(typeof(TEntity), (IEnumerable)node.UniqueEntities, ResourceHook.BeforeDelete, relationships) ?? node.UniqueEntities; var affected = new AffectedResources(targetEntities, node.PrincipalsToNextLayer()); IEnumerable updated = container.BeforeDelete(affected, pipeline); @@ -251,7 +253,8 @@ void FireNestedBeforeUpdateHooks(ResourcePipeline pipeline, EntityChildLayer lay { if (uniqueEntities.Cast().Any()) { - var dbValues = LoadDbValues(entityType, uniqueEntities, ResourceHook.BeforeUpdateRelationship, node.RelationshipsToNextLayer); + var relationships = node.RelationshipsToNextLayer.Select(p => p.Attribute).ToArray(); + var dbValues = LoadDbValues(entityType, uniqueEntities, ResourceHook.BeforeUpdateRelationship, relationships); var resourcesByRelationship = CreateRelationshipHelper(entityType, node.RelationshipsFromPreviousLayer.GetDependentEntities(), dbValues); var allowedIds = CallHook(nestedHookcontainer, ResourceHook.BeforeUpdateRelationship, new object[] { GetIds(uniqueEntities), resourcesByRelationship, pipeline }).Cast(); var updated = GetAllowedEntities(uniqueEntities, allowedIds); @@ -281,7 +284,7 @@ void FireNestedBeforeUpdateHooks(ResourcePipeline pipeline, EntityChildLayer lay /// Given a source of entities, gets the implicitly affected entities /// from the database and calls the BeforeImplicitUpdateRelationship hook. /// - void FireForAffectedImplicits(Type entityTypeToInclude, Dictionary implicitsTarget, ResourcePipeline pipeline, IEnumerable existingImplicitEntities = null) + void FireForAffectedImplicits(Type entityTypeToInclude, Dictionary implicitsTarget, ResourcePipeline pipeline, IEnumerable existingImplicitEntities = null) { var container = _executorHelper.GetResourceHookContainer(entityTypeToInclude, ResourceHook.BeforeImplicitUpdateRelationship); if (container == null) return; @@ -310,10 +313,10 @@ void ValidateHookResponse(IEnumerable returnedList, ResourcePipeline pipel /// NOTE: in JADNC usage, the root layer is ALWAYS homogenous, so we can be sure that for every /// relationship to the previous layer, the principal type is the same. /// - (Dictionary, PrincipalType) GetDependentImplicitsTargets(Dictionary dependentEntities) + (Dictionary, PrincipalType) GetDependentImplicitsTargets(Dictionary dependentEntities) { PrincipalType principalType = dependentEntities.First().Key.PrincipalType; - var byInverseRelationship = dependentEntities.Where(kvp => kvp.Key.Attribute.InverseNavigation != null).ToDictionary(kvp => GetInverseRelationship(kvp.Key), kvp => kvp.Value); + var byInverseRelationship = dependentEntities.Where(kvp => kvp.Key.InverseNavigation != null).ToDictionary(kvp => GetInverseRelationship(kvp.Key), kvp => kvp.Value); return (byInverseRelationship, principalType); } @@ -350,17 +353,17 @@ object ThrowJsonApiExceptionOnError(Func action) /// If are included, the values of the entries in need to be replaced with these values. /// /// The relationship helper. - IAffectedRelationships CreateRelationshipHelper(DependentType entityType, Dictionary prevLayerRelationships, IEnumerable dbValues = null) + IAffectedRelationships CreateRelationshipHelper(DependentType entityType, Dictionary prevLayerRelationships, IEnumerable dbValues = null) { if (dbValues != null) ReplaceWithDbValues(prevLayerRelationships, dbValues.Cast()); - return (IAffectedRelationships)TypeHelper.CreateInstanceOfOpenType(typeof(AffectedRelationships<>), entityType, true, prevLayerRelationships); + return (IAffectedRelationships)TypeHelper.CreateInstanceOfOpenType(typeof(AffectedRelationships<>), entityType, prevLayerRelationships); } /// /// Replaces the entities in the values of the prevLayerRelationships dictionary /// with the corresponding entities loaded from the db. /// - void ReplaceWithDbValues(Dictionary prevLayerRelationships, IEnumerable dbValues) + void ReplaceWithDbValues(Dictionary prevLayerRelationships, IEnumerable dbValues) { foreach (var key in prevLayerRelationships.Keys.ToList()) { @@ -379,14 +382,14 @@ HashSet GetAllowedEntities(IEnumerable source, IEnumerable - /// Gets the inverse for + /// Gets the inverse for /// - RelationshipProxy GetInverseRelationship(RelationshipProxy proxy) + RelationshipAttribute GetInverseRelationship(RelationshipAttribute attribute) { - return new RelationshipProxy(_graph.GetInverseRelationship(proxy.Attribute), proxy.PrincipalType, false); + return _graph.GetInverseRelationship(attribute); } - IEnumerable LoadDbValues(Type containerEntityType, IEnumerable uniqueEntities, ResourceHook targetHook, RelationshipProxy[] relationshipsToNextLayer) + IEnumerable LoadDbValues(Type containerEntityType, IEnumerable uniqueEntities, ResourceHook targetHook, RelationshipAttribute[] relationshipsToNextLayer) { if (!_executorHelper.ShouldLoadDbValues(containerEntityType, targetHook)) return null; return _executorHelper.LoadDbValues(containerEntityType, uniqueEntities, targetHook, relationshipsToNextLayer); diff --git a/src/JsonApiDotNetCore/Hooks/Traversal/RelationshipsFromPreviousLayer.cs b/src/JsonApiDotNetCore/Hooks/Traversal/RelationshipsFromPreviousLayer.cs index 95a96cf524..cb4185d1fd 100644 --- a/src/JsonApiDotNetCore/Hooks/Traversal/RelationshipsFromPreviousLayer.cs +++ b/src/JsonApiDotNetCore/Hooks/Traversal/RelationshipsFromPreviousLayer.cs @@ -14,12 +14,12 @@ internal interface IRelationshipsFromPreviousLayer /// Grouped by relationship to the previous layer, gets all the entities of the current layer /// /// The dependent entities. - Dictionary GetDependentEntities(); + Dictionary GetDependentEntities(); /// /// Grouped by relationship to the previous layer, gets all the entities of the previous layer /// /// The dependent entities. - Dictionary GetPrincipalEntities(); + Dictionary GetPrincipalEntities(); } internal class RelationshipsFromPreviousLayer : IRelationshipsFromPreviousLayer, IEnumerable> where TDependent : class, IIdentifiable @@ -31,14 +31,14 @@ public RelationshipsFromPreviousLayer(IEnumerable> _collection = collection; } - public Dictionary GetDependentEntities() + public Dictionary GetDependentEntities() { - return _collection.ToDictionary(rg => rg.Proxy, rg => (IEnumerable)rg.DependentEntities); + return _collection.ToDictionary(rg => rg.Proxy.Attribute, rg => (IEnumerable)rg.DependentEntities); } - public Dictionary GetPrincipalEntities() + public Dictionary GetPrincipalEntities() { - return _collection.ToDictionary(rg => rg.Proxy, rg => (IEnumerable)rg.PrincipalEntities); + return _collection.ToDictionary(rg => rg.Proxy.Attribute, rg => (IEnumerable)rg.PrincipalEntities); } public IEnumerator> GetEnumerator() diff --git a/src/JsonApiDotNetCore/Hooks/Traversal/RootNode.cs b/src/JsonApiDotNetCore/Hooks/Traversal/RootNode.cs index d13640a956..a7965f1ec9 100644 --- a/src/JsonApiDotNetCore/Hooks/Traversal/RootNode.cs +++ b/src/JsonApiDotNetCore/Hooks/Traversal/RootNode.cs @@ -17,19 +17,19 @@ internal class RootNode : IEntityNode where TEntity : class, IIdentifia public Type EntityType { get; internal set; } public IEnumerable UniqueEntities { get { return _uniqueEntities; } } public RelationshipProxy[] RelationshipsToNextLayer { get; private set; } - public Dictionary> PrincipalsToNextLayerByType() + public Dictionary> PrincipalsToNextLayerByType() { return RelationshipsToNextLayer .GroupBy(proxy => proxy.DependentType) - .ToDictionary(gdc => gdc.Key, gdc => gdc.ToDictionary(p => p, p => UniqueEntities)); + .ToDictionary(gdc => gdc.Key, gdc => gdc.ToDictionary(p => p.Attribute, p => UniqueEntities)); } /// /// The current layer entities grouped by affected relationship to the next layer /// - public Dictionary PrincipalsToNextLayer() + public Dictionary PrincipalsToNextLayer() { - return RelationshipsToNextLayer.ToDictionary(p => p, p => UniqueEntities); + return RelationshipsToNextLayer.ToDictionary(p => p.Attribute, p => UniqueEntities); } /// diff --git a/src/JsonApiDotNetCore/Internal/ResourceGraph.cs b/src/JsonApiDotNetCore/Internal/ResourceGraph.cs index a7bd486a65..efec077536 100644 --- a/src/JsonApiDotNetCore/Internal/ResourceGraph.cs +++ b/src/JsonApiDotNetCore/Internal/ResourceGraph.cs @@ -69,6 +69,11 @@ public interface IResourceGraph /// /// The internal attribute name for a . string GetPublicAttributeName(string internalAttributeName); + + /// + /// Helper method to get the inverse relationship attribute corresponding + /// to a relationship. + /// RelationshipAttribute GetInverseRelationship(RelationshipAttribute relationship); /// From 85cd5c7db6cb55d19fbf8ed98b553e349ac41f35 Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 20 Jun 2019 08:13:54 +0200 Subject: [PATCH 03/10] fix: made constructors public --- src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs index 6151f10314..053f051c79 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs @@ -18,7 +18,7 @@ public class AffectedResources : AffectedRelationships, IAffec /// public HashSet Entities { get; } - internal AffectedResources(IEnumerable entities, + public AffectedResources(IEnumerable entities, Dictionary relationships) : base(relationships) { Entities = new HashSet(entities.Cast()); From b3fbe751ae9f539bb16fca1270ea5ca8b2728bd4 Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 20 Jun 2019 09:39:17 +0200 Subject: [PATCH 04/10] chore: rename affected resource helpers, add comments --- .../Hooks/Execution/AffectedResourceDiff.cs | 12 +++++++----- src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs | 2 +- .../Update/BeforeUpdate_WithDbValues_Tests.cs | 2 +- .../ResourceHooks/ResourceHooksTestsSetup.cs | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs index 4825210a81..cb4226f5c3 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs @@ -17,10 +17,10 @@ namespace JsonApiDotNetCore.Hooks public interface IAffectedResourcesDiff : IAffectedResources where TEntity : class, IIdentifiable { HashSet DatabaseValues { get; } - IEnumerable> GetDiff(); + IEnumerable> GetDiffs(); } - public class ResourceDiff : AffectedResources, IAffectedResourcesDiff where TEntity : class, IIdentifiable + public class AffectedResourceDiff : AffectedResources, IAffectedResourcesDiff where TEntity : class, IIdentifiable { private readonly HashSet _databaseValues; @@ -31,7 +31,7 @@ public class ResourceDiff : AffectedResources, IAffectedResou /// public HashSet DatabaseValues { get => _databaseValues ?? ThrowNoDbValuesError(); } - public ResourceDiff(IEnumerable requestEntities, + public AffectedResourceDiff(IEnumerable requestEntities, IEnumerable databaseEntities, Dictionary relationships) : base(requestEntities, relationships) { @@ -39,12 +39,14 @@ public ResourceDiff(IEnumerable requestEntities, _databaseValuesLoaded |= _databaseValues != null; } - public IEnumerable> GetDiff() + public IEnumerable> GetDiffs() { + if (!_databaseValuesLoaded) ThrowNoDbValuesError(); + foreach (var entity in Entities) { TEntity currentValueInDatabase = null; - if (_databaseValuesLoaded) currentValueInDatabase = _databaseValues.Single(e => entity.StringId == e.StringId); + currentValueInDatabase = _databaseValues.Single(e => entity.StringId == e.StringId); yield return new ResourceDiffPair(entity, currentValueInDatabase); } } diff --git a/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs b/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs index 154eada525..3633dca119 100644 --- a/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs +++ b/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs @@ -49,7 +49,7 @@ public virtual IEnumerable BeforeUpdate(IEnumerable e { var relationships = node.RelationshipsToNextLayer.Select(p => p.Attribute).ToArray(); var dbValues = LoadDbValues(typeof(TEntity), (IEnumerable)node.UniqueEntities, ResourceHook.BeforeUpdate, relationships); - var diff = new ResourceDiff(node.UniqueEntities, dbValues, node.PrincipalsToNextLayer()); + var diff = new AffectedResourceDiff(node.UniqueEntities, dbValues, node.PrincipalsToNextLayer()); IEnumerable updated = container.BeforeUpdate(diff, pipeline); node.UpdateUnique(updated); node.Reassign(entities); diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs index 42b7151a07..4bf03a2e1f 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs @@ -210,7 +210,7 @@ public void BeforeUpdate_NoImplicit_Without_Child_Hook_Implemented() private bool TodoCheck(IAffectedResourcesDiff diff, string checksum) { - var diffPair = diff.GetDiff().Single(); + var diffPair = diff.GetDiffs().Single(); var dbCheck = diffPair.DatabaseValue.Description == checksum; var reqCheck = diffPair.Entity.Description == null; return (dbCheck && reqCheck); diff --git a/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs b/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs index 02b473b448..3131ee9052 100644 --- a/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs +++ b/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs @@ -262,7 +262,7 @@ void MockHooks(Mock> resourceDefinition) .Verifiable(); resourceDefinition .Setup(rd => rd.BeforeUpdate(It.IsAny>(), It.IsAny())) - .Returns, ResourcePipeline>((entityDiff, context) => entityDiff.Entities) + .Returns, ResourcePipeline>((entityDiff, context) => entityDiff.Entities) .Verifiable(); resourceDefinition .Setup(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny())) From 201a83728aae91b4c55b2201f062634d2f1d8f51 Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 20 Jun 2019 11:42:40 +0200 Subject: [PATCH 05/10] feat: affectedresource helpers easier to use in unit tests --- .../Resources/TagResource.cs | 5 + .../Hooks/Execution/AffectedRelationships.cs | 89 +++++++++++-- .../Hooks/Execution/AffectedResourceDiff.cs | 71 +++++++---- .../Hooks/Execution/AffectedResources.cs | 40 ++++-- .../Hooks/Execution/HookExecutorHelper.cs | 7 +- .../Hooks/IResourceHookContainer.cs | 120 ++++++++++-------- .../Hooks/ResourceHookExecutor.cs | 13 +- src/JsonApiDotNetCore/Internal/TypeHelper.cs | 10 +- .../UnitTests/ResourceHooks/DiscoveryTests.cs | 2 +- .../Create/BeforeCreate_WithDbValues_Tests.cs | 6 +- .../Update/BeforeUpdate_WithDbValues_Tests.cs | 2 +- .../ResourceHooks/ResourceHooksTestsSetup.cs | 2 +- 12 files changed, 248 insertions(+), 119 deletions(-) diff --git a/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs b/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs index 99769feade..8a1fe8c7df 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs @@ -13,6 +13,11 @@ public TagResource(IResourceGraph graph) : base(graph) { } + public override IEnumerable BeforeCreate(IAffectedResources affected, ResourcePipeline pipeline) + { + return base.BeforeCreate(affected, pipeline); + } + public override IEnumerable OnReturn(HashSet entities, ResourcePipeline pipeline) { return entities.Where(t => t.Name != "This should be not be included"); diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs index e37195ea5e..1ae78ee4d4 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using JsonApiDotNetCore.Models; @@ -11,44 +12,104 @@ public interface IAffectedRelationships { } /// /// A helper class that provides insights in which relationships have been updated for which entities. /// - public interface IAffectedRelationships : IAffectedRelationships where TDependent : class, IIdentifiable + public interface IAffectedRelationships : IAffectedRelationships where TDependentResource : class, IIdentifiable { /// /// Gets a dictionary of all entities grouped by affected relationship. /// - Dictionary> AllByRelationships(); + Dictionary> AllByRelationships(); /// - /// Gets a dictionary of all entities that have an affected relationship to type + /// Gets a dictionary of all entities that have an affected relationship to type /// - Dictionary> GetByRelationship() where TPrincipal : class, IIdentifiable; + Dictionary> GetByRelationship() where TPrincipalResource : class, IIdentifiable; /// /// Gets a dictionary of all entities that have an affected relationship to type /// - Dictionary> GetByRelationship(Type principalType); + Dictionary> GetByRelationship(Type principalType); } - public class AffectedRelationships : IAffectedRelationships where TDependent : class, IIdentifiable + /// + public class AffectedRelationships : IAffectedRelationships where TDependentResource : class, IIdentifiable { - private readonly Dictionary> _groups; + internal static Dictionary> ConvertRelationshipDictionary(Dictionary relationships) + { + return relationships.ToDictionary(pair => pair.Key, pair => (HashSet)pair.Value); + } + + /// + /// a dictionary with affected relationships as keys and values being the corresponding resources + /// that were affected + /// + private readonly Dictionary> _groups; - public Dictionary> AllByRelationships() + /// + public AffectedRelationships(Dictionary> relationships) { - return _groups; + _groups = relationships; } - public AffectedRelationships(Dictionary relationships) + + /// + /// Used internally by the ResourceHookExecutor to make live a bit easier with generics + /// + internal AffectedRelationships(Dictionary relationships) : this(ConvertRelationshipDictionary(relationships)) { } + + public Dictionary> AllByRelationships() { - _groups = relationships.ToDictionary(kvp => kvp.Key, kvp => new HashSet((IEnumerable)kvp.Value)); + return _groups; } - public Dictionary> GetByRelationship() where TPrincipal : class, IIdentifiable + /// + public Dictionary> GetByRelationship() where TPrincipalResource : class, IIdentifiable { - return GetByRelationship(typeof(TPrincipal)); + return GetByRelationship(typeof(TPrincipalResource)); } - public Dictionary> GetByRelationship(Type principalType) + /// + public Dictionary> GetByRelationship(Type principalType) { return _groups?.Where(p => p.Key.PrincipalType == principalType).ToDictionary(p => p.Key, p => p.Value); } } + + ///// + //public class AffectedRelationships : ReadOnlyDictionary>, IAffectedRelationships where TDependentResource : class, IIdentifiable + //{ + // private readonly Dictionary> _groups; + + // private static IDictionary> test(Dictionary relationship) + // { + // return relationship.ToDictionary(kvp => kvp.Key, kvp => new HashSet((IEnumerable)kvp.Value)); + // } + + // public AffectedRelationships(Dictionary relationship) : base(test(relationship)) + // { + // } + + + // /// + // public AffectedRelationships(Dictionary relationships) + // { + // _groups = relationships.ToDictionary(kvp => kvp.Key, kvp => new HashSet((IEnumerable)kvp.Value)); + // } + + // public Dictionary> AllByRelationships() + // { + // return _groups; + // } + + + + // /// + // public Dictionary> GetByRelationship() where TPrincipalResource : class, IIdentifiable + // { + // return GetByRelationship(typeof(TPrincipalResource)); + // } + + // /// + // public Dictionary> GetByRelationship(Type principalType) + // { + // return _groups?.Where(p => p.Key.PrincipalType == principalType).ToDictionary(p => p.Key, p => p.Value); + // } + //} } diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs index cb4226f5c3..d86343aa46 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs @@ -14,58 +14,83 @@ namespace JsonApiDotNetCore.Hooks /// Any relationships that are updated can be retrieved via the methods implemented on /// . /// - public interface IAffectedResourcesDiff : IAffectedResources where TEntity : class, IIdentifiable + public interface IAffectedResourcesDiff : IAffectedResources where TResource : class, IIdentifiable { - HashSet DatabaseValues { get; } - IEnumerable> GetDiffs(); + /// + /// the current database values of the affected resources collection. + /// + HashSet DatabaseValues { get; } + + /// + /// Matches the resources from the request to the database values that have been loaded + /// and exposes them in ResourceDiffPair wrapper + /// + IEnumerable> GetDiffs(); } - public class AffectedResourceDiff : AffectedResources, IAffectedResourcesDiff where TEntity : class, IIdentifiable + public class AffectedResourceDiff : AffectedResources, IAffectedResourcesDiff where TResource : class, IIdentifiable { - private readonly HashSet _databaseValues; + private readonly HashSet _databaseValues; private readonly bool _databaseValuesLoaded; - /// - /// the current database values of the affected resources collection. - /// - public HashSet DatabaseValues { get => _databaseValues ?? ThrowNoDbValuesError(); } - public AffectedResourceDiff(IEnumerable requestEntities, - IEnumerable databaseEntities, - Dictionary relationships) : base(requestEntities, relationships) + /// + public HashSet DatabaseValues { get => _databaseValues ?? ThrowNoDbValuesError(); } + + public AffectedResourceDiff(HashSet requestEntities, + HashSet databaseEntities, + Dictionary> relationships) : base(requestEntities, relationships) { - _databaseValues = (HashSet)databaseEntities; + _databaseValues = databaseEntities; _databaseValuesLoaded |= _databaseValues != null; } - public IEnumerable> GetDiffs() + /// + /// Used internally by the ResourceHookExecutor to make live a bit easier with generics + /// + internal AffectedResourceDiff(IEnumerable requestEntities, + IEnumerable databaseEntities, + Dictionary relationships) + : this((HashSet)requestEntities, (HashSet)databaseEntities, ConvertRelationshipDictionary(relationships)) { } + + /// + public IEnumerable> GetDiffs() { if (!_databaseValuesLoaded) ThrowNoDbValuesError(); - foreach (var entity in Entities) + foreach (var entity in Resources) { - TEntity currentValueInDatabase = null; + TResource currentValueInDatabase = null; currentValueInDatabase = _databaseValues.Single(e => entity.StringId == e.StringId); - yield return new ResourceDiffPair(entity, currentValueInDatabase); + yield return new ResourceDiffPair(entity, currentValueInDatabase); } } - private HashSet ThrowNoDbValuesError() + private HashSet ThrowNoDbValuesError() { throw new MemberAccessException("Cannot access database entities if the LoadDatabaseValues option is set to false"); } } - public class ResourceDiffPair where TEntity : class, IIdentifiable + /// + /// A wrapper that contains a resource from the request matches to its current database value + /// + public class ResourceDiffPair where TResource : class, IIdentifiable { - public ResourceDiffPair(TEntity entity, TEntity databaseValue) + public ResourceDiffPair(TResource resource, TResource databaseValue) { - Entity = entity; + Resource = resource; DatabaseValue = databaseValue; } - public TEntity Entity { get; private set; } - public TEntity DatabaseValue { get; private set; } + /// + /// The resource from the request matching the resource from the database. + /// + public TResource Resource { get; private set; } + /// + /// The resource from the database matching the resource from the request. + /// + public TResource DatabaseValue { get; private set; } } } diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs index 053f051c79..a26641efe3 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs @@ -5,29 +5,43 @@ namespace JsonApiDotNetCore.Hooks { - - public interface IAffectedResources : IEnumerable where TEntity : class, IIdentifiable - { - HashSet Entities { get; } - } - - public class AffectedResources : AffectedRelationships, IAffectedResources where TEntity : class, IIdentifiable + /// + /// Basically just a list of , but also contains information + /// about updated relationships through inheritance of IAffectedRelationships> + /// + public interface IAffectedResources : IAffectedRelationships, IEnumerable where TResource : class, IIdentifiable { /// /// The entities that are affected by the request. /// - public HashSet Entities { get; } + HashSet Resources { get; } + } - public AffectedResources(IEnumerable entities, - Dictionary relationships) : base(relationships) + public class AffectedResources : AffectedRelationships, IAffectedResources where TResource : class, IIdentifiable + { + /// + public HashSet Resources { get; } + + public AffectedResources(HashSet entities, + Dictionary> relationships) : base(relationships) { - Entities = new HashSet(entities.Cast()); + Resources = new HashSet(entities.Cast()); } - public IEnumerator GetEnumerator() + + /// + /// Used internally by the ResourceHookExecutor to make live a bit easier with generics + /// + internal AffectedResources(IEnumerable entities, + Dictionary relationships) + : this((HashSet)entities, ConvertRelationshipDictionary(relationships)) { } + + /// + public IEnumerator GetEnumerator() { - return Entities.GetEnumerator(); + return Resources.GetEnumerator(); } + /// IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); diff --git a/src/JsonApiDotNetCore/Hooks/Execution/HookExecutorHelper.cs b/src/JsonApiDotNetCore/Hooks/Execution/HookExecutorHelper.cs index 99e9ce23b1..6a2c2767bf 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/HookExecutorHelper.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/HookExecutorHelper.cs @@ -206,10 +206,15 @@ public Dictionary LoadImplicitlyAffected( } } - return implicitlyAffected.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + return implicitlyAffected.ToDictionary(kvp => kvp.Key, kvp => TypeHelper.CreateHashSetFor(kvp.Key.DependentType, kvp.Value)); } + private IEnumerable CreateHashSet(Type type, IList elements) + { + return (IEnumerable)Activator.CreateInstance(typeof(HashSet<>).MakeGenericType(type), new object[] { elements }); + } + bool IsHasManyThrough(KeyValuePair kvp, out IEnumerable entities, out RelationshipAttribute attr) diff --git a/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs b/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs index 7597a02d6e..f469a7b487 100644 --- a/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs +++ b/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs @@ -14,61 +14,6 @@ public interface IResourceHookContainer { } /// public interface IResourceHookContainer : IBeforeHooks, IAfterHooks, IOnHooks, IResourceHookContainer where TEntity : class, IIdentifiable { } - /// - /// Wrapper interface for all After hooks. - /// - public interface IAfterHooks where TEntity : class, IIdentifiable - { - /// - /// Implement this hook to run custom logic in the - /// layer just after creation of entities of type . - /// - /// If relationships were created with the created entities, this will - /// be reflected by the corresponding NavigationProperty being set. - /// For each of these relationships, the - /// hook is fired after the execution of this hook. - /// - /// The transformed entity set - /// The unique set of affected entities. - /// An enum indicating from where the hook was triggered. - void AfterCreate(HashSet entities, ResourcePipeline pipeline); - /// - /// Implement this hook to run custom logic in the - /// layer just after reading entities of type . - /// - /// The unique set of affected entities. - /// An enum indicating from where the hook was triggered. - /// A boolean to indicate whether the entities in this hook execution are the main entities of the request, - /// or if they were included as a relationship - void AfterRead(HashSet entities, ResourcePipeline pipeline, bool isIncluded = false); - /// - /// Implement this hook to run custom logic in the - /// layer just after updating entities of type . - /// - /// If relationships were updated with the updated entities, this will - /// be reflected by the corresponding NavigationProperty being set. - /// For each of these relationships, the - /// hook is fired after the execution of this hook. - /// - /// The unique set of affected entities. - /// An enum indicating from where the hook was triggered. - void AfterUpdate(HashSet entities, ResourcePipeline pipeline); - /// - /// Implement this hook to run custom logic in the - /// layer just after deletion of entities of type . - /// - /// The unique set of affected entities. - /// An enum indicating from where the hook was triggered. - /// If set to true if the deletion was succeeded in the repository layer. - void AfterDelete(HashSet entities, ResourcePipeline pipeline, bool succeeded); - /// - /// Implement this hook to run custom logic in the layer - /// just after a relationship was updated. - /// - /// Relationship helper. - /// An enum indicating from where the hook was triggered. - void AfterUpdateRelationship(IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline); - } /// /// Wrapper interface for all Before hooks. @@ -115,7 +60,7 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// multiple entities. /// /// The returned may be a subset - /// of the property in parameter , + /// of the property in parameter , /// in which case the operation of the pipeline will not be executed /// for the omitted entities. The returned set may also contain custom /// changes of the properties on the entities. @@ -134,6 +79,7 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// The entity diff. /// An enum indicating from where the hook was triggered. IEnumerable BeforeUpdate(IAffectedResourcesDiff ResourceDiff, ResourcePipeline pipeline); + /// /// Implement this hook to run custom logic in the /// layer just before deleting entities of type . @@ -197,6 +143,68 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable void BeforeImplicitUpdateRelationship(IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline); } + + + + + + + /// + /// Wrapper interface for all After hooks. + /// + public interface IAfterHooks where TEntity : class, IIdentifiable + { + /// + /// Implement this hook to run custom logic in the + /// layer just after creation of entities of type . + /// + /// If relationships were created with the created entities, this will + /// be reflected by the corresponding NavigationProperty being set. + /// For each of these relationships, the + /// hook is fired after the execution of this hook. + /// + /// The transformed entity set + /// The unique set of affected entities. + /// An enum indicating from where the hook was triggered. + void AfterCreate(HashSet entities, ResourcePipeline pipeline); + /// + /// Implement this hook to run custom logic in the + /// layer just after reading entities of type . + /// + /// The unique set of affected entities. + /// An enum indicating from where the hook was triggered. + /// A boolean to indicate whether the entities in this hook execution are the main entities of the request, + /// or if they were included as a relationship + void AfterRead(HashSet entities, ResourcePipeline pipeline, bool isIncluded = false); + /// + /// Implement this hook to run custom logic in the + /// layer just after updating entities of type . + /// + /// If relationships were updated with the updated entities, this will + /// be reflected by the corresponding NavigationProperty being set. + /// For each of these relationships, the + /// hook is fired after the execution of this hook. + /// + /// The unique set of affected entities. + /// An enum indicating from where the hook was triggered. + void AfterUpdate(HashSet entities, ResourcePipeline pipeline); + /// + /// Implement this hook to run custom logic in the + /// layer just after deletion of entities of type . + /// + /// The unique set of affected entities. + /// An enum indicating from where the hook was triggered. + /// If set to true if the deletion was succeeded in the repository layer. + void AfterDelete(HashSet entities, ResourcePipeline pipeline, bool succeeded); + /// + /// Implement this hook to run custom logic in the layer + /// just after a relationship was updated. + /// + /// Relationship helper. + /// An enum indicating from where the hook was triggered. + void AfterUpdateRelationship(IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline); + } + /// /// Wrapper interface for all on hooks. /// diff --git a/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs b/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs index 3633dca119..709cee9128 100644 --- a/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs +++ b/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs @@ -355,21 +355,24 @@ object ThrowJsonApiExceptionOnError(Func action) /// The relationship helper. IAffectedRelationships CreateRelationshipHelper(DependentType entityType, Dictionary prevLayerRelationships, IEnumerable dbValues = null) { - if (dbValues != null) ReplaceWithDbValues(prevLayerRelationships, dbValues.Cast()); - return (IAffectedRelationships)TypeHelper.CreateInstanceOfOpenType(typeof(AffectedRelationships<>), entityType, prevLayerRelationships); + Dictionary prevLayerRelationshipsCasted = null; + if (dbValues != null) prevLayerRelationships = ReplaceWithDbValues(prevLayerRelationships, dbValues.Cast()); + prevLayerRelationshipsCasted = prevLayerRelationshipsCasted ?? prevLayerRelationships; + return (IAffectedRelationships)TypeHelper.CreateInstanceOfOpenType(typeof(AffectedRelationships<>), entityType, true, prevLayerRelationships); } /// /// Replaces the entities in the values of the prevLayerRelationships dictionary /// with the corresponding entities loaded from the db. /// - void ReplaceWithDbValues(Dictionary prevLayerRelationships, IEnumerable dbValues) + Dictionary ReplaceWithDbValues(Dictionary prevLayerRelationships, IEnumerable dbValues) { foreach (var key in prevLayerRelationships.Keys.ToList()) { var replaced = prevLayerRelationships[key].Cast().Select(entity => dbValues.Single(dbEntity => dbEntity.StringId == entity.StringId)).Cast(key.DependentType); - prevLayerRelationships[key] = replaced; + prevLayerRelationships[key] = TypeHelper.CreateHashSetFor(key.DependentType, replaced); } + return prevLayerRelationships; } /// @@ -389,7 +392,7 @@ RelationshipAttribute GetInverseRelationship(RelationshipAttribute attribute) return _graph.GetInverseRelationship(attribute); } - IEnumerable LoadDbValues(Type containerEntityType, IEnumerable uniqueEntities, ResourceHook targetHook, RelationshipAttribute[] relationshipsToNextLayer) + IEnumerable LoadDbValues(Type containerEntityType, IEnumerable uniqueEntities, ResourceHook targetHook, RelationshipAttribute[] relationshipsToNextLayer) { if (!_executorHelper.ShouldLoadDbValues(containerEntityType, targetHook)) return null; return _executorHelper.LoadDbValues(containerEntityType, uniqueEntities, targetHook, relationshipsToNextLayer); diff --git a/src/JsonApiDotNetCore/Internal/TypeHelper.cs b/src/JsonApiDotNetCore/Internal/TypeHelper.cs index 7677862efb..5ef6e4a4cd 100644 --- a/src/JsonApiDotNetCore/Internal/TypeHelper.cs +++ b/src/JsonApiDotNetCore/Internal/TypeHelper.cs @@ -147,9 +147,17 @@ public static object CreateInstanceOfOpenType(Type openType, Type parameter, boo /// The target type public static IList CreateListFor(Type type) { - IList list = (IList)CreateInstanceOfOpenType(typeof(List<>), type ); + IList list = (IList)CreateInstanceOfOpenType(typeof(List<>), type); return list; + } + /// + /// Reflectively instantiates a hashset of a certain type. + /// + /// + public static IEnumerable CreateHashSetFor(Type type, object elements = null) + { + return (IEnumerable)CreateInstanceOfOpenType(typeof(HashSet<>), type, elements ?? new object()); } /// diff --git a/test/UnitTests/ResourceHooks/DiscoveryTests.cs b/test/UnitTests/ResourceHooks/DiscoveryTests.cs index 6af4f6a392..725c2fc4da 100644 --- a/test/UnitTests/ResourceHooks/DiscoveryTests.cs +++ b/test/UnitTests/ResourceHooks/DiscoveryTests.cs @@ -81,7 +81,7 @@ public class DoubleDummyResourceDefinition1 : ResourceDefinition { public DoubleDummyResourceDefinition1() : base(new ResourceGraphBuilder().AddResource().Build()) { } - public override IEnumerable BeforeDelete(IAffectedResources affected, ResourcePipeline pipeline) { return affected.Entities; } + public override IEnumerable BeforeDelete(IAffectedResources affected, ResourcePipeline pipeline) { return affected.Resources; } } public class DoubleDummyResourceDefinition2 : ResourceDefinition { diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs index 11d1af329a..38e2e49fbf 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs @@ -61,7 +61,7 @@ public void BeforeCreate() ResourcePipeline.Post), Times.Once()); todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( - It.Is>(rh => TodoCheck(rh, description + description)), + It.Is>(rh => TodoCheckRelationships(rh, description + description)), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -103,7 +103,7 @@ public void BeforeCreate_Without_Child_Hook_Implemented() // assert todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( - It.Is>(rh => TodoCheck(rh, description + description)), + It.Is>(rh => TodoCheckRelationships(rh, description + description)), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -174,7 +174,7 @@ private bool TodoCheck(IEnumerable entities, string checksum) return entities.Single().Description == checksum; } - private bool TodoCheck(IAffectedRelationships rh, string checksum) + private bool TodoCheckRelationships(IAffectedRelationships rh, string checksum) { return rh.GetByRelationship().Single().Value.First().Description == checksum; } diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs index 4bf03a2e1f..6995333412 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs @@ -212,7 +212,7 @@ private bool TodoCheck(IAffectedResourcesDiff diff, string checksum) { var diffPair = diff.GetDiffs().Single(); var dbCheck = diffPair.DatabaseValue.Description == checksum; - var reqCheck = diffPair.Entity.Description == null; + var reqCheck = diffPair.Resource.Description == null; return (dbCheck && reqCheck); } diff --git a/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs b/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs index 3131ee9052..ea06799935 100644 --- a/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs +++ b/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs @@ -262,7 +262,7 @@ void MockHooks(Mock> resourceDefinition) .Verifiable(); resourceDefinition .Setup(rd => rd.BeforeUpdate(It.IsAny>(), It.IsAny())) - .Returns, ResourcePipeline>((entityDiff, context) => entityDiff.Entities) + .Returns, ResourcePipeline>((entityDiff, context) => entityDiff.Resources) .Verifiable(); resourceDefinition .Setup(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny())) From 79b25decdd74525a2f47ff0f064bfc10edc9cf86 Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 20 Jun 2019 11:44:56 +0200 Subject: [PATCH 06/10] chore: rm unused code --- .../Hooks/Execution/AffectedRelationships.cs | 45 ++----------------- 1 file changed, 3 insertions(+), 42 deletions(-) diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs index 1ae78ee4d4..fe57e830c7 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs @@ -18,7 +18,6 @@ public interface IAffectedRelationships : IAffectedRelations /// Gets a dictionary of all entities grouped by affected relationship. /// Dictionary> AllByRelationships(); - /// /// Gets a dictionary of all entities that have an affected relationship to type /// @@ -32,6 +31,9 @@ public interface IAffectedRelationships : IAffectedRelations /// public class AffectedRelationships : IAffectedRelationships where TDependentResource : class, IIdentifiable { + /// + /// Helper method that "unboxes" the TValue from the relationship dictionary + /// internal static Dictionary> ConvertRelationshipDictionary(Dictionary relationships) { return relationships.ToDictionary(pair => pair.Key, pair => (HashSet)pair.Value); @@ -71,45 +73,4 @@ public Dictionary> GetByRelat return _groups?.Where(p => p.Key.PrincipalType == principalType).ToDictionary(p => p.Key, p => p.Value); } } - - ///// - //public class AffectedRelationships : ReadOnlyDictionary>, IAffectedRelationships where TDependentResource : class, IIdentifiable - //{ - // private readonly Dictionary> _groups; - - // private static IDictionary> test(Dictionary relationship) - // { - // return relationship.ToDictionary(kvp => kvp.Key, kvp => new HashSet((IEnumerable)kvp.Value)); - // } - - // public AffectedRelationships(Dictionary relationship) : base(test(relationship)) - // { - // } - - - // /// - // public AffectedRelationships(Dictionary relationships) - // { - // _groups = relationships.ToDictionary(kvp => kvp.Key, kvp => new HashSet((IEnumerable)kvp.Value)); - // } - - // public Dictionary> AllByRelationships() - // { - // return _groups; - // } - - - - // /// - // public Dictionary> GetByRelationship() where TPrincipalResource : class, IIdentifiable - // { - // return GetByRelationship(typeof(TPrincipalResource)); - // } - - // /// - // public Dictionary> GetByRelationship(Type principalType) - // { - // return _groups?.Where(p => p.Key.PrincipalType == principalType).ToDictionary(p => p.Key, p => p.Value); - // } - //} } From 833d0e32cbd9ef35fcf650b5cb559682b0191f4a Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 20 Jun 2019 11:45:41 +0200 Subject: [PATCH 07/10] chore: rm spaces --- .../Hooks/Execution/AffectedResourceDiff.cs | 5 +---- src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs index d86343aa46..8f0a96e247 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs @@ -30,17 +30,14 @@ public interface IAffectedResourcesDiff : IAffectedResources : AffectedResources, IAffectedResourcesDiff where TResource : class, IIdentifiable { - private readonly HashSet _databaseValues; private readonly bool _databaseValuesLoaded; - - /// public HashSet DatabaseValues { get => _databaseValues ?? ThrowNoDbValuesError(); } public AffectedResourceDiff(HashSet requestEntities, HashSet databaseEntities, - Dictionary> relationships) : base(requestEntities, relationships) + Dictionary> relationships) : base(requestEntities, relationships) { _databaseValues = databaseEntities; _databaseValuesLoaded |= _databaseValues != null; diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs index a26641efe3..7ea3fb51a6 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs @@ -47,5 +47,4 @@ IEnumerator IEnumerable.GetEnumerator() return GetEnumerator(); } } - } \ No newline at end of file From 9935a869c04efd528aa9cd4e7ad3c3828afb914f Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 20 Jun 2019 15:21:51 +0200 Subject: [PATCH 08/10] feat: relationshipdictionary now actually inherits from dictionary --- .../Resources/PassportResource.cs | 2 +- .../Resources/PersonResource.cs | 4 +- .../Resources/TodoResource.cs | 2 +- .../Hooks/Execution/AffectedResources.cs | 43 ++++++++------ ...ourceDiff.cs => AffectedResourcesDiffs.cs} | 58 +++++++++++++------ ...ionships.cs => RelationshipsDictionary.cs} | 44 +++++++------- .../Hooks/IResourceHookContainer.cs | 14 ++--- .../Hooks/ResourceHookExecutor.cs | 6 +- src/JsonApiDotNetCore/Internal/TypeHelper.cs | 13 ++++- .../Models/ResourceDefinition.cs | 8 +-- .../JsonApiDotNetCoreExampleTests.csproj | 2 +- .../UnitTests/ResourceHooks/DiscoveryTests.cs | 2 +- .../Create/AfterCreateTests.cs | 4 +- .../Create/BeforeCreateTests.cs | 4 +- .../Create/BeforeCreate_WithDbValues_Tests.cs | 16 ++--- .../Delete/BeforeDelete_WithDbValue_Tests.cs | 12 ++-- .../Update/AfterUpdateTests.cs | 4 +- .../Update/BeforeUpdateTests.cs | 8 +-- .../Update/BeforeUpdate_WithDbValues_Tests.cs | 36 ++++++------ .../ResourceHooks/ResourceHooksTestsSetup.cs | 10 ++-- 20 files changed, 167 insertions(+), 125 deletions(-) rename src/JsonApiDotNetCore/Hooks/Execution/{AffectedResourceDiff.cs => AffectedResourcesDiffs.cs} (52%) rename src/JsonApiDotNetCore/Hooks/Execution/{AffectedRelationships.cs => RelationshipsDictionary.cs} (54%) mode change 100755 => 100644 test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj diff --git a/src/Examples/JsonApiDotNetCoreExample/Resources/PassportResource.cs b/src/Examples/JsonApiDotNetCoreExample/Resources/PassportResource.cs index b1a86bf4b8..457468c484 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Resources/PassportResource.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Resources/PassportResource.cs @@ -22,7 +22,7 @@ public override void BeforeRead(ResourcePipeline pipeline, bool isIncluded = fal } } - public override void BeforeImplicitUpdateRelationship(IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline) + public override void BeforeImplicitUpdateRelationship(IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline) { resourcesByRelationship.GetByRelationship().ToList().ForEach(kvp => DoesNotTouchLockedPassports(kvp.Value)); } diff --git a/src/Examples/JsonApiDotNetCoreExample/Resources/PersonResource.cs b/src/Examples/JsonApiDotNetCoreExample/Resources/PersonResource.cs index 50e9efb54c..032c9acb4b 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Resources/PersonResource.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Resources/PersonResource.cs @@ -10,7 +10,7 @@ public class PersonResource : LockableResourceBase { public PersonResource(IResourceGraph graph) : base(graph) { } - public override IEnumerable BeforeUpdateRelationship(HashSet ids, IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline) + public override IEnumerable BeforeUpdateRelationship(HashSet ids, IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline) { BeforeImplicitUpdateRelationship(resourcesByRelationship, pipeline); return ids; @@ -22,7 +22,7 @@ public override IEnumerable BeforeUpdateRelationship(HashSet ids // return entityDiff.Entities; //} - public override void BeforeImplicitUpdateRelationship(IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline) + public override void BeforeImplicitUpdateRelationship(IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline) { resourcesByRelationship.GetByRelationship().ToList().ForEach(kvp => DisallowLocked(kvp.Value)); } diff --git a/src/Examples/JsonApiDotNetCoreExample/Resources/TodoResource.cs b/src/Examples/JsonApiDotNetCoreExample/Resources/TodoResource.cs index 1de3a02a6a..02a7ba6f15 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Resources/TodoResource.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Resources/TodoResource.cs @@ -19,7 +19,7 @@ public override void BeforeRead(ResourcePipeline pipeline, bool isIncluded = fal } } - public override void BeforeImplicitUpdateRelationship(IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline) + public override void BeforeImplicitUpdateRelationship(IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline) { List todos = resourcesByRelationship.GetByRelationship().SelectMany(kvp => kvp.Value).ToList(); DisallowLocked(todos); diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs index 7ea3fb51a6..22f5609eec 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs @@ -2,30 +2,38 @@ using JsonApiDotNetCore.Models; using System.Linq; using System.Collections; +using JsonApiDotNetCore.Internal; +using System; namespace JsonApiDotNetCore.Hooks { /// - /// Basically just a list of , but also contains information - /// about updated relationships through inheritance of IAffectedRelationships> + /// Basically a enumerable of of resources that were affected by the request. + /// + /// Also contains information about updated relationships through + /// implementation of IAffectedRelationshipsDictionary> /// - public interface IAffectedResources : IAffectedRelationships, IEnumerable where TResource : class, IIdentifiable + public interface IAffectedResources : IRelationshipsDictionary, IEnumerable where TResource : class, IIdentifiable { - /// - /// The entities that are affected by the request. - /// - HashSet Resources { get; } + } - public class AffectedResources : AffectedRelationships, IAffectedResources where TResource : class, IIdentifiable + /// + /// Implementation of IAffectedResources{TResource}. + /// + /// It is basically just a HashSet{TResource} that also stores the + /// RelationshipDictionary{TResource} and the same helper methods to access this + /// dictionary as defined on IAffectedRelationshipsDictionary{TResource}. + /// + public class AffectedResources : HashSet, IAffectedResources where TResource : class, IIdentifiable { /// - public HashSet Resources { get; } + public RelationshipsDictionary AffectedRelationships { get; private set; } public AffectedResources(HashSet entities, - Dictionary> relationships) : base(relationships) + Dictionary> relationships) : base(entities) { - Resources = new HashSet(entities.Cast()); + AffectedRelationships = new RelationshipsDictionary(relationships); } /// @@ -33,18 +41,17 @@ public AffectedResources(HashSet entities, /// internal AffectedResources(IEnumerable entities, Dictionary relationships) - : this((HashSet)entities, ConvertRelationshipDictionary(relationships)) { } + : this((HashSet)entities, TypeHelper.ConvertRelationshipDictionary(relationships)) { } - /// - public IEnumerator GetEnumerator() + + public Dictionary> GetByRelationship(Type principalType) { - return Resources.GetEnumerator(); + return AffectedRelationships.GetByRelationship(principalType); } - /// - IEnumerator IEnumerable.GetEnumerator() + public Dictionary> GetByRelationship() where TPrincipalResource : class, IIdentifiable { - return GetEnumerator(); + return GetByRelationship(); } } } \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourcesDiffs.cs similarity index 52% rename from src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs rename to src/JsonApiDotNetCore/Hooks/Execution/AffectedResourcesDiffs.cs index 8f0a96e247..5db8815744 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourcesDiffs.cs @@ -2,43 +2,50 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; namespace JsonApiDotNetCore.Hooks { /// - /// A helper class that provides insight in what is to be updated. The - /// property reflects what was parsed from the incoming request, - /// where the reflects what is the current state in the database. + /// A wrapper class that contains information about the resources that are updated by the request. + /// Contains the resources from the request and the corresponding database values. /// - /// Any relationships that are updated can be retrieved via the methods implemented on - /// . + /// Also contains information about updated relationships through + /// implementation of IAffectedRelationshipsDictionary> /// - public interface IAffectedResourcesDiff : IAffectedResources where TResource : class, IIdentifiable + public interface IAffectedResourcesDiffs : IRelationshipsDictionary, IEnumerable> where TResource : class, IIdentifiable { /// - /// the current database values of the affected resources collection. + /// The database values of the resources affected by the request. /// HashSet DatabaseValues { get; } /// - /// Matches the resources from the request to the database values that have been loaded - /// and exposes them in ResourceDiffPair wrapper + /// The resources that were affected by the request. /// - IEnumerable> GetDiffs(); + HashSet Resources { get; } } - public class AffectedResourceDiff : AffectedResources, IAffectedResourcesDiff where TResource : class, IIdentifiable + /// + public class AffectedResourcesDiffs : IAffectedResourcesDiffs where TResource : class, IIdentifiable { private readonly HashSet _databaseValues; private readonly bool _databaseValuesLoaded; + /// public HashSet DatabaseValues { get => _databaseValues ?? ThrowNoDbValuesError(); } + /// + public HashSet Resources { get; private set; } + /// + public RelationshipsDictionary AffectedRelationships { get; private set; } - public AffectedResourceDiff(HashSet requestEntities, + public AffectedResourcesDiffs(HashSet requestEntities, HashSet databaseEntities, - Dictionary> relationships) : base(requestEntities, relationships) + Dictionary> relationships) { + Resources = requestEntities; + AffectedRelationships = new RelationshipsDictionary(relationships); _databaseValues = databaseEntities; _databaseValuesLoaded |= _databaseValues != null; } @@ -46,13 +53,26 @@ public AffectedResourceDiff(HashSet requestEntities, /// /// Used internally by the ResourceHookExecutor to make live a bit easier with generics /// - internal AffectedResourceDiff(IEnumerable requestEntities, + internal AffectedResourcesDiffs(IEnumerable requestEntities, IEnumerable databaseEntities, Dictionary relationships) - : this((HashSet)requestEntities, (HashSet)databaseEntities, ConvertRelationshipDictionary(relationships)) { } + : this((HashSet)requestEntities, (HashSet)databaseEntities, TypeHelper.ConvertRelationshipDictionary(relationships)) { } + + + /// + public Dictionary> GetByRelationship() where TPrincipalResource : class, IIdentifiable + { + return GetByRelationship(typeof(TPrincipalResource)); + } /// - public IEnumerable> GetDiffs() + public Dictionary> GetByRelationship(Type principalType) + { + return AffectedRelationships.GetByRelationship(principalType); + } + + /// + public IEnumerator> GetEnumerator() { if (!_databaseValuesLoaded) ThrowNoDbValuesError(); @@ -64,6 +84,9 @@ public IEnumerable> GetDiffs() } } + /// + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + private HashSet ThrowNoDbValuesError() { throw new MemberAccessException("Cannot access database entities if the LoadDatabaseValues option is set to false"); @@ -71,7 +94,8 @@ private HashSet ThrowNoDbValuesError() } /// - /// A wrapper that contains a resource from the request matches to its current database value + /// A wrapper that contains an resource that is affected by the request, + /// matched to its current database value /// public class ResourceDiffPair where TResource : class, IIdentifiable { diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs b/src/JsonApiDotNetCore/Hooks/Execution/RelationshipsDictionary.cs similarity index 54% rename from src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs rename to src/JsonApiDotNetCore/Hooks/Execution/RelationshipsDictionary.cs index fe57e830c7..c742aa97d6 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/RelationshipsDictionary.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using JsonApiDotNetCore.Internal; using JsonApiDotNetCore.Models; namespace JsonApiDotNetCore.Hooks @@ -10,14 +11,21 @@ namespace JsonApiDotNetCore.Hooks public interface IAffectedRelationships { } /// - /// A helper class that provides insights in which relationships have been updated for which entities. + /// An interface that is implemented to expose a relationship dictionary on another class. /// - public interface IAffectedRelationships : IAffectedRelationships where TDependentResource : class, IIdentifiable + public interface IRelationshipsDictionary : IRelationshipsDictionaryGetters where TDependentResource : class, IIdentifiable { /// - /// Gets a dictionary of all entities grouped by affected relationship. + /// Gets a dictionary of affected resources grouped by affected relationships. /// - Dictionary> AllByRelationships(); + RelationshipsDictionary AffectedRelationships { get; } + } + + /// + /// A helper class that provides insights in which relationships have been updated for which entities. + /// + public interface IRelationshipsDictionaryGetters : IAffectedRelationships where TDependentResource : class, IIdentifiable + { /// /// Gets a dictionary of all entities that have an affected relationship to type /// @@ -28,17 +36,14 @@ public interface IAffectedRelationships : IAffectedRelations Dictionary> GetByRelationship(Type principalType); } - /// - public class AffectedRelationships : IAffectedRelationships where TDependentResource : class, IIdentifiable + /// + /// Implementation of IAffectedRelationships{TDependentResource} + /// + /// It is practically a ReadOnlyDictionary{RelationshipAttribute, HashSet{TDependentResource}} dictionary + /// with the two helper methods defined on IAffectedRelationships{TDependentResource}. + /// + public class RelationshipsDictionary : ReadOnlyDictionary>, IRelationshipsDictionaryGetters where TDependentResource : class, IIdentifiable { - /// - /// Helper method that "unboxes" the TValue from the relationship dictionary - /// - internal static Dictionary> ConvertRelationshipDictionary(Dictionary relationships) - { - return relationships.ToDictionary(pair => pair.Key, pair => (HashSet)pair.Value); - } - /// /// a dictionary with affected relationships as keys and values being the corresponding resources /// that were affected @@ -46,7 +51,7 @@ internal static Dictionary> C private readonly Dictionary> _groups; /// - public AffectedRelationships(Dictionary> relationships) + public RelationshipsDictionary(Dictionary> relationships) : base(relationships) { _groups = relationships; } @@ -54,12 +59,9 @@ public AffectedRelationships(Dictionary /// Used internally by the ResourceHookExecutor to make live a bit easier with generics /// - internal AffectedRelationships(Dictionary relationships) : this(ConvertRelationshipDictionary(relationships)) { } + internal RelationshipsDictionary(Dictionary relationships) + : this(TypeHelper.ConvertRelationshipDictionary(relationships)) { } - public Dictionary> AllByRelationships() - { - return _groups; - } /// public Dictionary> GetByRelationship() where TPrincipalResource : class, IIdentifiable @@ -70,7 +72,7 @@ public Dictionary> GetByRelat /// public Dictionary> GetByRelationship(Type principalType) { - return _groups?.Where(p => p.Key.PrincipalType == principalType).ToDictionary(p => p.Key, p => p.Value); + return this.Where(p => p.Key.PrincipalType == principalType).ToDictionary(p => p.Key, p => p.Value); } } } diff --git a/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs b/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs index f469a7b487..3bfe58e96f 100644 --- a/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs +++ b/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs @@ -60,7 +60,7 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// multiple entities. /// /// The returned may be a subset - /// of the property in parameter , + /// of the property in parameter , /// in which case the operation of the pipeline will not be executed /// for the omitted entities. The returned set may also contain custom /// changes of the properties on the entities. @@ -78,7 +78,7 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// The transformed entity set /// The entity diff. /// An enum indicating from where the hook was triggered. - IEnumerable BeforeUpdate(IAffectedResourcesDiff ResourceDiff, ResourcePipeline pipeline); + IEnumerable BeforeUpdate(IAffectedResourcesDiffs ResourceDiff, ResourcePipeline pipeline); /// /// Implement this hook to run custom logic in the @@ -121,7 +121,7 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// The unique set of ids /// An enum indicating from where the hook was triggered. /// A helper that groups the entities by the affected relationship - IEnumerable BeforeUpdateRelationship(HashSet ids, IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline); + IEnumerable BeforeUpdateRelationship(HashSet ids, IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline); /// /// Implement this hook to run custom logic in the /// layer just before implicitly updating relationships to entities of type . @@ -140,7 +140,7 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// The transformed set of ids /// A helper that groups the entities by the affected relationship /// An enum indicating from where the hook was triggered. - void BeforeImplicitUpdateRelationship(IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline); + void BeforeImplicitUpdateRelationship(IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline); } @@ -160,7 +160,7 @@ public interface IAfterHooks where TEntity : class, IIdentifiable /// /// If relationships were created with the created entities, this will /// be reflected by the corresponding NavigationProperty being set. - /// For each of these relationships, the + /// For each of these relationships, the /// hook is fired after the execution of this hook. /// /// The transformed entity set @@ -182,7 +182,7 @@ public interface IAfterHooks where TEntity : class, IIdentifiable /// /// If relationships were updated with the updated entities, this will /// be reflected by the corresponding NavigationProperty being set. - /// For each of these relationships, the + /// For each of these relationships, the /// hook is fired after the execution of this hook. /// /// The unique set of affected entities. @@ -202,7 +202,7 @@ public interface IAfterHooks where TEntity : class, IIdentifiable /// /// Relationship helper. /// An enum indicating from where the hook was triggered. - void AfterUpdateRelationship(IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline); + void AfterUpdateRelationship(IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline); } /// diff --git a/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs b/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs index 709cee9128..f7eb6f9a39 100644 --- a/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs +++ b/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs @@ -49,7 +49,7 @@ public virtual IEnumerable BeforeUpdate(IEnumerable e { var relationships = node.RelationshipsToNextLayer.Select(p => p.Attribute).ToArray(); var dbValues = LoadDbValues(typeof(TEntity), (IEnumerable)node.UniqueEntities, ResourceHook.BeforeUpdate, relationships); - var diff = new AffectedResourceDiff(node.UniqueEntities, dbValues, node.PrincipalsToNextLayer()); + var diff = new AffectedResourcesDiffs(node.UniqueEntities, dbValues, node.PrincipalsToNextLayer()); IEnumerable updated = container.BeforeUpdate(diff, pipeline); node.UpdateUnique(updated); node.Reassign(entities); @@ -355,10 +355,8 @@ object ThrowJsonApiExceptionOnError(Func action) /// The relationship helper. IAffectedRelationships CreateRelationshipHelper(DependentType entityType, Dictionary prevLayerRelationships, IEnumerable dbValues = null) { - Dictionary prevLayerRelationshipsCasted = null; if (dbValues != null) prevLayerRelationships = ReplaceWithDbValues(prevLayerRelationships, dbValues.Cast()); - prevLayerRelationshipsCasted = prevLayerRelationshipsCasted ?? prevLayerRelationships; - return (IAffectedRelationships)TypeHelper.CreateInstanceOfOpenType(typeof(AffectedRelationships<>), entityType, true, prevLayerRelationships); + return (IAffectedRelationships)TypeHelper.CreateInstanceOfOpenType(typeof(RelationshipsDictionary<>), entityType, true, prevLayerRelationships); } /// diff --git a/src/JsonApiDotNetCore/Internal/TypeHelper.cs b/src/JsonApiDotNetCore/Internal/TypeHelper.cs index 5ef6e4a4cd..cf642aa395 100644 --- a/src/JsonApiDotNetCore/Internal/TypeHelper.cs +++ b/src/JsonApiDotNetCore/Internal/TypeHelper.cs @@ -1,11 +1,13 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Reflection; +using JsonApiDotNetCore.Models; namespace JsonApiDotNetCore.Internal { - public static class TypeHelper + internal static class TypeHelper { public static IList ConvertCollection(IEnumerable collection, Type targetType) { @@ -107,6 +109,15 @@ public static object CreateInstanceOfOpenType(Type openType, Type[] parameters, return Activator.CreateInstance(parameterizedType, constructorArguments); } + + /// + /// Helper method that "unboxes" the TValue from the relationship dictionary into + /// + public static Dictionary> ConvertRelationshipDictionary(Dictionary relationships) + { + return relationships.ToDictionary(pair => pair.Key, pair => (HashSet)pair.Value); + } + /// /// Use this overload if you need to instantiate a type that has a internal constructor /// diff --git a/src/JsonApiDotNetCore/Models/ResourceDefinition.cs b/src/JsonApiDotNetCore/Models/ResourceDefinition.cs index c8fbec627d..45092a3786 100644 --- a/src/JsonApiDotNetCore/Models/ResourceDefinition.cs +++ b/src/JsonApiDotNetCore/Models/ResourceDefinition.cs @@ -173,19 +173,19 @@ public virtual void AfterUpdate(HashSet entities, ResourcePipeline pipeline) /// public virtual void AfterDelete(HashSet entities, ResourcePipeline pipeline, bool succeeded) { } /// - public virtual void AfterUpdateRelationship(IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline) { } + public virtual void AfterUpdateRelationship(IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline) { } /// public virtual IEnumerable BeforeCreate(IAffectedResources affected, ResourcePipeline pipeline) { return affected; } /// public virtual void BeforeRead(ResourcePipeline pipeline, bool isIncluded = false, string stringId = null) { } /// - public virtual IEnumerable BeforeUpdate(IAffectedResourcesDiff ResourceDiff, ResourcePipeline pipeline) { return ResourceDiff; } + public virtual IEnumerable BeforeUpdate(IAffectedResourcesDiffs ResourceDiff, ResourcePipeline pipeline) { return ResourceDiff.Resources; } /// public virtual IEnumerable BeforeDelete(IAffectedResources affected, ResourcePipeline pipeline) { return affected; } /// - public virtual IEnumerable BeforeUpdateRelationship(HashSet ids, IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline) { return ids; } + public virtual IEnumerable BeforeUpdateRelationship(HashSet ids, IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline) { return ids; } /// - public virtual void BeforeImplicitUpdateRelationship(IAffectedRelationships resourcesByRelationship, ResourcePipeline pipeline) { } + public virtual void BeforeImplicitUpdateRelationship(IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline) { } /// public virtual IEnumerable OnReturn(HashSet entities, ResourcePipeline pipeline) { return entities; } diff --git a/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj b/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj old mode 100755 new mode 100644 index bf27086a63..b4fcaf7ae0 --- a/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj +++ b/test/JsonApiDotNetCoreExampleTests/JsonApiDotNetCoreExampleTests.csproj @@ -17,7 +17,7 @@ - + diff --git a/test/UnitTests/ResourceHooks/DiscoveryTests.cs b/test/UnitTests/ResourceHooks/DiscoveryTests.cs index 725c2fc4da..d686eaba73 100644 --- a/test/UnitTests/ResourceHooks/DiscoveryTests.cs +++ b/test/UnitTests/ResourceHooks/DiscoveryTests.cs @@ -81,7 +81,7 @@ public class DoubleDummyResourceDefinition1 : ResourceDefinition { public DoubleDummyResourceDefinition1() : base(new ResourceGraphBuilder().AddResource().Build()) { } - public override IEnumerable BeforeDelete(IAffectedResources affected, ResourcePipeline pipeline) { return affected.Resources; } + public override IEnumerable BeforeDelete(IAffectedResources affected, ResourcePipeline pipeline) { return affected; } } public class DoubleDummyResourceDefinition2 : ResourceDefinition { diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/AfterCreateTests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/AfterCreateTests.cs index ca7b78f86d..dea114facc 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/AfterCreateTests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/AfterCreateTests.cs @@ -25,7 +25,7 @@ public void AfterCreate() // assert todoResourceMock.Verify(rd => rd.AfterCreate(It.IsAny>(), ResourcePipeline.Post), Times.Once()); - ownerResourceMock.Verify(rd => rd.AfterUpdateRelationship(It.IsAny>(), ResourcePipeline.Post), Times.Once()); + ownerResourceMock.Verify(rd => rd.AfterUpdateRelationship(It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } @@ -43,7 +43,7 @@ public void AfterCreate_Without_Parent_Hook_Implemented() hookExecutor.AfterCreate(todoList, ResourcePipeline.Post); // assert - ownerResourceMock.Verify(rd => rd.AfterUpdateRelationship(It.IsAny>(), ResourcePipeline.Post), Times.Once()); + ownerResourceMock.Verify(rd => rd.AfterUpdateRelationship(It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreateTests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreateTests.cs index 4a35411171..e3a775e536 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreateTests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreateTests.cs @@ -25,7 +25,7 @@ public void BeforeCreate() hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Once()); - ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Post), Times.Once()); + ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } @@ -44,7 +44,7 @@ public void BeforeCreate_Without_Parent_Hook_Implemented() hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Never()); - ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Post), Times.Once()); + ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } [Fact] diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs index 38e2e49fbf..827901de63 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs @@ -57,11 +57,11 @@ public void BeforeCreate() todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), - It.IsAny>(), + It.IsAny>(), ResourcePipeline.Post), Times.Once()); todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( - It.Is>(rh => TodoCheckRelationships(rh, description + description)), + It.Is>(rh => TodoCheckRelationships(rh, description + description)), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -82,7 +82,7 @@ public void BeforeCreate_Without_Parent_Hook_Implemented() // assert ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), - It.IsAny>(), + It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -103,7 +103,7 @@ public void BeforeCreate_Without_Child_Hook_Implemented() // assert todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( - It.Is>(rh => TodoCheckRelationships(rh, description + description)), + It.Is>(rh => TodoCheckRelationships(rh, description + description)), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -125,7 +125,7 @@ public void BeforeCreate_NoImplicit() todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), - It.IsAny>(), + It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -146,7 +146,7 @@ public void BeforeCreate_NoImplicit_Without_Parent_Hook_Implemented() // assert ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), - It.IsAny>(), + It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -174,7 +174,7 @@ private bool TodoCheck(IEnumerable entities, string checksum) return entities.Single().Description == checksum; } - private bool TodoCheckRelationships(IAffectedRelationships rh, string checksum) + private bool TodoCheckRelationships(IRelationshipsDictionary rh, string checksum) { return rh.GetByRelationship().Single().Value.First().Description == checksum; } @@ -184,7 +184,7 @@ private bool PersonIdCheck(IEnumerable ids, string checksum) return ids.Single() == checksum; } - private bool PersonCheck(string checksum, IAffectedRelationships helper) + private bool PersonCheck(string checksum, IRelationshipsDictionary helper) { var entries = helper.GetByRelationship(); diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDelete_WithDbValue_Tests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDelete_WithDbValue_Tests.cs index 7c23e8d133..88a2c0127d 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDelete_WithDbValue_Tests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDelete_WithDbValue_Tests.cs @@ -48,8 +48,8 @@ public void BeforeDelete() // assert personResourceMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); - todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship(It.Is>( rh => CheckImplicitTodos(rh) ), ResourcePipeline.Delete), Times.Once()); - passportResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship(It.Is>( rh => CheckImplicitPassports(rh) ), ResourcePipeline.Delete), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship(It.Is>( rh => CheckImplicitTodos(rh) ), ResourcePipeline.Delete), Times.Once()); + passportResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship(It.Is>( rh => CheckImplicitPassports(rh) ), ResourcePipeline.Delete), Times.Once()); VerifyNoOtherCalls(personResourceMock, todoResourceMock, passportResourceMock); } @@ -68,8 +68,8 @@ public void BeforeDelete_No_Parent_Hooks() hookExecutor.BeforeDelete(new List { person }, ResourcePipeline.Delete); // assert - todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship(It.Is>(rh => CheckImplicitTodos(rh)), ResourcePipeline.Delete), Times.Once()); - passportResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship(It.Is>(rh => CheckImplicitPassports(rh)), ResourcePipeline.Delete), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship(It.Is>(rh => CheckImplicitTodos(rh)), ResourcePipeline.Delete), Times.Once()); + passportResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship(It.Is>(rh => CheckImplicitPassports(rh)), ResourcePipeline.Delete), Times.Once()); VerifyNoOtherCalls(personResourceMock, todoResourceMock, passportResourceMock); } @@ -92,13 +92,13 @@ public void BeforeDelete_No_Children_Hooks() VerifyNoOtherCalls(personResourceMock, todoResourceMock, passportResourceMock); } - private bool CheckImplicitTodos(IAffectedRelationships rh) + private bool CheckImplicitTodos(IRelationshipsDictionary rh) { var todos = rh.GetByRelationship().ToList(); return todos.Count == 2; } - private bool CheckImplicitPassports(IAffectedRelationships rh) + private bool CheckImplicitPassports(IRelationshipsDictionary rh) { var passports = rh.GetByRelationship().Single().Value; return passports.Count == 1; diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/AfterUpdateTests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/AfterUpdateTests.cs index e9c7f98473..e8d4f4fd60 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/AfterUpdateTests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/AfterUpdateTests.cs @@ -25,7 +25,7 @@ public void AfterUpdate() // assert todoResourceMock.Verify(rd => rd.AfterUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); - ownerResourceMock.Verify(rd => rd.AfterUpdateRelationship(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); + ownerResourceMock.Verify(rd => rd.AfterUpdateRelationship(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } @@ -43,7 +43,7 @@ public void AfterUpdate_Without_Parent_Hook_Implemented() hookExecutor.AfterUpdate(todoList, ResourcePipeline.Patch); // assert - ownerResourceMock.Verify(rd => rd.AfterUpdateRelationship(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); + ownerResourceMock.Verify(rd => rd.AfterUpdateRelationship(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdateTests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdateTests.cs index 67195f2d95..b5049b6fe6 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdateTests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdateTests.cs @@ -24,8 +24,8 @@ public void BeforeUpdate() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); - ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); + ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } @@ -43,7 +43,7 @@ public void BeforeUpdate_Without_Parent_Hook_Implemented() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Patch), Times.Once()); + ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } @@ -62,7 +62,7 @@ public void BeforeUpdate_Without_Child_Hook_Implemented() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs index 6995333412..2bbc977d62 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs @@ -59,18 +59,18 @@ public void BeforeUpdate() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), - It.Is>(rh => PersonCheck(lastName, rh)), + It.Is>(rh => PersonCheck(lastName, rh)), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( - It.Is>(rh => PersonCheck(lastName + lastName, rh)), + It.Is>(rh => PersonCheck(lastName + lastName, rh)), ResourcePipeline.Patch), Times.Once()); todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( - It.Is>( rh => TodoCheck(rh, description + description)), + It.Is>( rh => TodoCheck(rh, description + description)), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -93,9 +93,9 @@ public void BeforeUpdate_Deleting_Relationship() hookExecutor.BeforeUpdate(_todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( - It.Is>(rh => PersonCheck(lastName + lastName, rh)), + It.Is>(rh => PersonCheck(lastName + lastName, rh)), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -117,11 +117,11 @@ public void BeforeUpdate_Without_Parent_Hook_Implemented() // assert ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), - It.Is>(rh => PersonCheck(lastName, rh)), + It.Is>(rh => PersonCheck(lastName, rh)), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( - It.Is>(rh => PersonCheck(lastName + lastName, rh)), + It.Is>(rh => PersonCheck(lastName + lastName, rh)), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -140,9 +140,9 @@ public void BeforeUpdate_Without_Child_Hook_Implemented() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( - It.Is>(rh => TodoCheck(rh, description + description)), + It.Is>(rh => TodoCheck(rh, description + description)), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -161,10 +161,10 @@ public void BeforeUpdate_NoImplicit() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), - It.IsAny>(), + It.IsAny>(), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -185,7 +185,7 @@ public void BeforeUpdate_NoImplicit_Without_Parent_Hook_Implemented() // assert ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), - It.Is>(rh => PersonCheck(lastName, rh)), + It.Is>(rh => PersonCheck(lastName, rh)), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); @@ -204,19 +204,19 @@ public void BeforeUpdate_NoImplicit_Without_Child_Hook_Implemented() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } - private bool TodoCheck(IAffectedResourcesDiff diff, string checksum) + private bool TodoCheck(IAffectedResourcesDiffs diff, string checksum) { - var diffPair = diff.GetDiffs().Single(); + var diffPair = diff.Single(); var dbCheck = diffPair.DatabaseValue.Description == checksum; var reqCheck = diffPair.Resource.Description == null; return (dbCheck && reqCheck); } - private bool TodoCheck(IAffectedRelationships rh, string checksum) + private bool TodoCheck(IRelationshipsDictionary rh, string checksum) { return rh.GetByRelationship().Single().Value.First().Description == checksum; } @@ -226,7 +226,7 @@ private bool PersonIdCheck(IEnumerable ids, string checksum) return ids.Single() == checksum; } - private bool PersonCheck(string checksum, IAffectedRelationships helper) + private bool PersonCheck(string checksum, IRelationshipsDictionary helper) { var entries = helper.GetByRelationship(); return entries.Single().Value.Single().LastName == checksum; diff --git a/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs b/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs index ea06799935..648bf5a8e4 100644 --- a/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs +++ b/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs @@ -261,19 +261,19 @@ void MockHooks(Mock> resourceDefinition) .Setup(rd => rd.BeforeRead(It.IsAny(), It.IsAny(), It.IsAny())) .Verifiable(); resourceDefinition - .Setup(rd => rd.BeforeUpdate(It.IsAny>(), It.IsAny())) - .Returns, ResourcePipeline>((entityDiff, context) => entityDiff.Resources) + .Setup(rd => rd.BeforeUpdate(It.IsAny>(), It.IsAny())) + .Returns, ResourcePipeline>((entityDiff, context) => entityDiff.Resources) .Verifiable(); resourceDefinition .Setup(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny())) .Returns, ResourcePipeline>((entities, context) => entities) .Verifiable(); resourceDefinition - .Setup(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), It.IsAny())) - .Returns, IAffectedRelationships, ResourcePipeline>((ids, context, helper) => ids) + .Setup(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), It.IsAny())) + .Returns, IRelationshipsDictionary, ResourcePipeline>((ids, context, helper) => ids) .Verifiable(); resourceDefinition - .Setup(rd => rd.BeforeImplicitUpdateRelationship(It.IsAny>(), It.IsAny())) + .Setup(rd => rd.BeforeImplicitUpdateRelationship(It.IsAny>(), It.IsAny())) .Verifiable(); resourceDefinition From 8a9056bc25f7ce9d2e394a48ae9e92565ad71bff Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Thu, 20 Jun 2019 15:49:47 +0200 Subject: [PATCH 09/10] feat: hook resource helpers that feel more intuitive --- .../Resources/TagResource.cs | 2 +- .../Execution/RelationshipsDictionary.cs | 8 ++++---- ...ctedResourcesDiffs.cs => ResourceDiffs.cs} | 14 +++++++------- ...ffectedResources.cs => ResourceHashSet.cs} | 19 +++++++++++-------- .../Hooks/IResourceHookContainer.cs | 8 ++++---- .../Hooks/ResourceHookExecutor.cs | 10 +++++----- .../Models/ResourceDefinition.cs | 6 +++--- .../UnitTests/ResourceHooks/DiscoveryTests.cs | 8 ++++---- .../Create/BeforeCreateTests.cs | 6 +++--- .../Create/BeforeCreate_WithDbValues_Tests.cs | 8 ++++---- .../Delete/BeforeDeleteTests.cs | 2 +- .../Delete/BeforeDelete_WithDbValue_Tests.cs | 4 ++-- .../Update/BeforeUpdateTests.cs | 4 ++-- .../Update/BeforeUpdate_WithDbValues_Tests.cs | 12 ++++++------ .../ResourceHooks/ResourceHooksTestsSetup.cs | 8 ++++---- 15 files changed, 61 insertions(+), 58 deletions(-) rename src/JsonApiDotNetCore/Hooks/Execution/{AffectedResourcesDiffs.cs => ResourceDiffs.cs} (88%) rename src/JsonApiDotNetCore/Hooks/Execution/{AffectedResources.cs => ResourceHashSet.cs} (68%) diff --git a/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs b/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs index 8a1fe8c7df..e12e04a297 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs @@ -13,7 +13,7 @@ public TagResource(IResourceGraph graph) : base(graph) { } - public override IEnumerable BeforeCreate(IAffectedResources affected, ResourcePipeline pipeline) + public override IEnumerable BeforeCreate(IResourceHashSet affected, ResourcePipeline pipeline) { return base.BeforeCreate(affected, pipeline); } diff --git a/src/JsonApiDotNetCore/Hooks/Execution/RelationshipsDictionary.cs b/src/JsonApiDotNetCore/Hooks/Execution/RelationshipsDictionary.cs index c742aa97d6..77248f5169 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/RelationshipsDictionary.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/RelationshipsDictionary.cs @@ -8,12 +8,12 @@ namespace JsonApiDotNetCore.Hooks { - public interface IAffectedRelationships { } + public interface IRelationshipsDictionary { } /// /// An interface that is implemented to expose a relationship dictionary on another class. /// - public interface IRelationshipsDictionary : IRelationshipsDictionaryGetters where TDependentResource : class, IIdentifiable + public interface IExposeRelationshipsDictionary : IRelationshipsDictionary where TDependentResource : class, IIdentifiable { /// /// Gets a dictionary of affected resources grouped by affected relationships. @@ -24,7 +24,7 @@ public interface IRelationshipsDictionary : IRelationshipsDi /// /// A helper class that provides insights in which relationships have been updated for which entities. /// - public interface IRelationshipsDictionaryGetters : IAffectedRelationships where TDependentResource : class, IIdentifiable + public interface IRelationshipsDictionary : IRelationshipsDictionary where TDependentResource : class, IIdentifiable { /// /// Gets a dictionary of all entities that have an affected relationship to type @@ -42,7 +42,7 @@ public interface IRelationshipsDictionaryGetters : IAffected /// It is practically a ReadOnlyDictionary{RelationshipAttribute, HashSet{TDependentResource}} dictionary /// with the two helper methods defined on IAffectedRelationships{TDependentResource}. /// - public class RelationshipsDictionary : ReadOnlyDictionary>, IRelationshipsDictionaryGetters where TDependentResource : class, IIdentifiable + public class RelationshipsDictionary : ReadOnlyDictionary>, IRelationshipsDictionary where TDependentResource : class, IIdentifiable { /// /// a dictionary with affected relationships as keys and values being the corresponding resources diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourcesDiffs.cs b/src/JsonApiDotNetCore/Hooks/Execution/ResourceDiffs.cs similarity index 88% rename from src/JsonApiDotNetCore/Hooks/Execution/AffectedResourcesDiffs.cs rename to src/JsonApiDotNetCore/Hooks/Execution/ResourceDiffs.cs index 5db8815744..b7d1a05550 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResourcesDiffs.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/ResourceDiffs.cs @@ -12,9 +12,9 @@ namespace JsonApiDotNetCore.Hooks /// Contains the resources from the request and the corresponding database values. /// /// Also contains information about updated relationships through - /// implementation of IAffectedRelationshipsDictionary> + /// implementation of IRelationshipsDictionary> /// - public interface IAffectedResourcesDiffs : IRelationshipsDictionary, IEnumerable> where TResource : class, IIdentifiable + public interface IResourceDiffs : IRelationshipsDictionary, IEnumerable> where TResource : class, IIdentifiable { /// /// The database values of the resources affected by the request. @@ -28,19 +28,19 @@ public interface IAffectedResourcesDiffs : IRelationshipsDictionary - public class AffectedResourcesDiffs : IAffectedResourcesDiffs where TResource : class, IIdentifiable + public class ResourceDiffs : IResourceDiffs where TResource : class, IIdentifiable { + /// + public HashSet DatabaseValues { get => _databaseValues ?? ThrowNoDbValuesError(); } private readonly HashSet _databaseValues; private readonly bool _databaseValuesLoaded; - /// - public HashSet DatabaseValues { get => _databaseValues ?? ThrowNoDbValuesError(); } /// public HashSet Resources { get; private set; } /// public RelationshipsDictionary AffectedRelationships { get; private set; } - public AffectedResourcesDiffs(HashSet requestEntities, + public ResourceDiffs(HashSet requestEntities, HashSet databaseEntities, Dictionary> relationships) { @@ -53,7 +53,7 @@ public AffectedResourcesDiffs(HashSet requestEntities, /// /// Used internally by the ResourceHookExecutor to make live a bit easier with generics /// - internal AffectedResourcesDiffs(IEnumerable requestEntities, + internal ResourceDiffs(IEnumerable requestEntities, IEnumerable databaseEntities, Dictionary relationships) : this((HashSet)requestEntities, (HashSet)databaseEntities, TypeHelper.ConvertRelationshipDictionary(relationships)) { } diff --git a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs b/src/JsonApiDotNetCore/Hooks/Execution/ResourceHashSet.cs similarity index 68% rename from src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs rename to src/JsonApiDotNetCore/Hooks/Execution/ResourceHashSet.cs index 22f5609eec..7fb83f3666 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/ResourceHashSet.cs @@ -13,24 +13,25 @@ namespace JsonApiDotNetCore.Hooks /// Also contains information about updated relationships through /// implementation of IAffectedRelationshipsDictionary> /// - public interface IAffectedResources : IRelationshipsDictionary, IEnumerable where TResource : class, IIdentifiable + public interface IResourceHashSet : IRelationshipsDictionary, IEnumerable where TResource : class, IIdentifiable { } /// - /// Implementation of IAffectedResources{TResource}. + /// Implementation of IResourceHashSet{TResource}. /// - /// It is basically just a HashSet{TResource} that also stores the - /// RelationshipDictionary{TResource} and the same helper methods to access this - /// dictionary as defined on IAffectedRelationshipsDictionary{TResource}. + /// Basically a enumerable of of resources that were affected by the request. + /// + /// Also contains information about updated relationships through + /// implementation of IRelationshipsDictionary> /// - public class AffectedResources : HashSet, IAffectedResources where TResource : class, IIdentifiable + public class ResourceHashSet : HashSet, IResourceHashSet where TResource : class, IIdentifiable { /// public RelationshipsDictionary AffectedRelationships { get; private set; } - public AffectedResources(HashSet entities, + public ResourceHashSet(HashSet entities, Dictionary> relationships) : base(entities) { AffectedRelationships = new RelationshipsDictionary(relationships); @@ -39,16 +40,18 @@ public AffectedResources(HashSet entities, /// /// Used internally by the ResourceHookExecutor to make live a bit easier with generics /// - internal AffectedResources(IEnumerable entities, + internal ResourceHashSet(IEnumerable entities, Dictionary relationships) : this((HashSet)entities, TypeHelper.ConvertRelationshipDictionary(relationships)) { } + /// public Dictionary> GetByRelationship(Type principalType) { return AffectedRelationships.GetByRelationship(principalType); } + /// public Dictionary> GetByRelationship() where TPrincipalResource : class, IIdentifiable { return GetByRelationship(); diff --git a/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs b/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs index 3bfe58e96f..139e3ca392 100644 --- a/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs +++ b/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs @@ -41,7 +41,7 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// The transformed entity set /// The unique set of affected entities. /// An enum indicating from where the hook was triggered. - IEnumerable BeforeCreate(IAffectedResources entities, ResourcePipeline pipeline); + IEnumerable BeforeCreate(IResourceHashSet entities, ResourcePipeline pipeline); /// /// Implement this hook to run custom logic in the /// layer just before reading entities of type . @@ -60,7 +60,7 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// multiple entities. /// /// The returned may be a subset - /// of the property in parameter , + /// of the property in parameter , /// in which case the operation of the pipeline will not be executed /// for the omitted entities. The returned set may also contain custom /// changes of the properties on the entities. @@ -78,7 +78,7 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// The transformed entity set /// The entity diff. /// An enum indicating from where the hook was triggered. - IEnumerable BeforeUpdate(IAffectedResourcesDiffs ResourceDiff, ResourcePipeline pipeline); + IEnumerable BeforeUpdate(IResourceDiffs ResourceDiff, ResourcePipeline pipeline); /// /// Implement this hook to run custom logic in the @@ -101,7 +101,7 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// The transformed entity set /// The unique set of affected entities. /// An enum indicating from where the hook was triggered. - IEnumerable BeforeDelete(IAffectedResources entities, ResourcePipeline pipeline); + IEnumerable BeforeDelete(IResourceHashSet entities, ResourcePipeline pipeline); /// /// Implement this hook to run custom logic in the /// layer just before updating relationships to entities of type . diff --git a/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs b/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs index f7eb6f9a39..5591b397be 100644 --- a/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs +++ b/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs @@ -49,7 +49,7 @@ public virtual IEnumerable BeforeUpdate(IEnumerable e { var relationships = node.RelationshipsToNextLayer.Select(p => p.Attribute).ToArray(); var dbValues = LoadDbValues(typeof(TEntity), (IEnumerable)node.UniqueEntities, ResourceHook.BeforeUpdate, relationships); - var diff = new AffectedResourcesDiffs(node.UniqueEntities, dbValues, node.PrincipalsToNextLayer()); + var diff = new ResourceDiffs(node.UniqueEntities, dbValues, node.PrincipalsToNextLayer()); IEnumerable updated = container.BeforeUpdate(diff, pipeline); node.UpdateUnique(updated); node.Reassign(entities); @@ -65,7 +65,7 @@ public virtual IEnumerable BeforeCreate(IEnumerable e { if (GetHook(ResourceHook.BeforeCreate, entities, out var container, out var node)) { - var affected = new AffectedResources((HashSet)node.UniqueEntities, node.PrincipalsToNextLayer()); + var affected = new ResourceHashSet((HashSet)node.UniqueEntities, node.PrincipalsToNextLayer()); IEnumerable updated = container.BeforeCreate(affected, pipeline); node.UpdateUnique(updated); node.Reassign(entities); @@ -82,7 +82,7 @@ public virtual IEnumerable BeforeDelete(IEnumerable e { var relationships = node.RelationshipsToNextLayer.Select(p => p.Attribute).ToArray(); var targetEntities = LoadDbValues(typeof(TEntity), (IEnumerable)node.UniqueEntities, ResourceHook.BeforeDelete, relationships) ?? node.UniqueEntities; - var affected = new AffectedResources(targetEntities, node.PrincipalsToNextLayer()); + var affected = new ResourceHashSet(targetEntities, node.PrincipalsToNextLayer()); IEnumerable updated = container.BeforeDelete(affected, pipeline); node.UpdateUnique(updated); @@ -353,10 +353,10 @@ object ThrowJsonApiExceptionOnError(Func action) /// If are included, the values of the entries in need to be replaced with these values. /// /// The relationship helper. - IAffectedRelationships CreateRelationshipHelper(DependentType entityType, Dictionary prevLayerRelationships, IEnumerable dbValues = null) + IRelationshipsDictionary CreateRelationshipHelper(DependentType entityType, Dictionary prevLayerRelationships, IEnumerable dbValues = null) { if (dbValues != null) prevLayerRelationships = ReplaceWithDbValues(prevLayerRelationships, dbValues.Cast()); - return (IAffectedRelationships)TypeHelper.CreateInstanceOfOpenType(typeof(RelationshipsDictionary<>), entityType, true, prevLayerRelationships); + return (IRelationshipsDictionary)TypeHelper.CreateInstanceOfOpenType(typeof(RelationshipsDictionary<>), entityType, true, prevLayerRelationships); } /// diff --git a/src/JsonApiDotNetCore/Models/ResourceDefinition.cs b/src/JsonApiDotNetCore/Models/ResourceDefinition.cs index 45092a3786..a4420465ed 100644 --- a/src/JsonApiDotNetCore/Models/ResourceDefinition.cs +++ b/src/JsonApiDotNetCore/Models/ResourceDefinition.cs @@ -175,13 +175,13 @@ public virtual void AfterDelete(HashSet entities, ResourcePipeline pipeline, /// public virtual void AfterUpdateRelationship(IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline) { } /// - public virtual IEnumerable BeforeCreate(IAffectedResources affected, ResourcePipeline pipeline) { return affected; } + public virtual IEnumerable BeforeCreate(IResourceHashSet affected, ResourcePipeline pipeline) { return affected; } /// public virtual void BeforeRead(ResourcePipeline pipeline, bool isIncluded = false, string stringId = null) { } /// - public virtual IEnumerable BeforeUpdate(IAffectedResourcesDiffs ResourceDiff, ResourcePipeline pipeline) { return ResourceDiff.Resources; } + public virtual IEnumerable BeforeUpdate(IResourceDiffs ResourceDiff, ResourcePipeline pipeline) { return ResourceDiff.Resources; } /// - public virtual IEnumerable BeforeDelete(IAffectedResources affected, ResourcePipeline pipeline) { return affected; } + public virtual IEnumerable BeforeDelete(IResourceHashSet affected, ResourcePipeline pipeline) { return affected; } /// public virtual IEnumerable BeforeUpdateRelationship(HashSet ids, IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline) { return ids; } /// diff --git a/test/UnitTests/ResourceHooks/DiscoveryTests.cs b/test/UnitTests/ResourceHooks/DiscoveryTests.cs index d686eaba73..8c8c4a7f4b 100644 --- a/test/UnitTests/ResourceHooks/DiscoveryTests.cs +++ b/test/UnitTests/ResourceHooks/DiscoveryTests.cs @@ -14,7 +14,7 @@ public class DummyResourceDefinition : ResourceDefinition { public DummyResourceDefinition() : base(new ResourceGraphBuilder().AddResource().Build()) { } - public override IEnumerable BeforeDelete(IAffectedResources affected, ResourcePipeline pipeline) { return affected; } + public override IEnumerable BeforeDelete(IResourceHashSet affected, ResourcePipeline pipeline) { return affected; } public override void AfterDelete(HashSet entities, ResourcePipeline pipeline, bool succeeded) { } } @@ -35,7 +35,7 @@ public abstract class ResourceDefintionBase : ResourceDefinition where T : { protected ResourceDefintionBase(IResourceGraph graph) : base(graph) { } - public override IEnumerable BeforeDelete(IAffectedResources affected, ResourcePipeline pipeline) { return affected; } + public override IEnumerable BeforeDelete(IResourceHashSet affected, ResourcePipeline pipeline) { return affected; } public override void AfterDelete(HashSet entities, ResourcePipeline pipeline, bool succeeded) { } } @@ -59,7 +59,7 @@ public class YetAnotherDummyResourceDefinition : ResourceDefinition().Build()) { } - public override IEnumerable BeforeDelete(IAffectedResources affected, ResourcePipeline pipeline) { return affected; } + public override IEnumerable BeforeDelete(IResourceHashSet affected, ResourcePipeline pipeline) { return affected; } [LoadDatabaseValues(false)] public override void AfterDelete(HashSet entities, ResourcePipeline pipeline, bool succeeded) { } @@ -81,7 +81,7 @@ public class DoubleDummyResourceDefinition1 : ResourceDefinition { public DoubleDummyResourceDefinition1() : base(new ResourceGraphBuilder().AddResource().Build()) { } - public override IEnumerable BeforeDelete(IAffectedResources affected, ResourcePipeline pipeline) { return affected; } + public override IEnumerable BeforeDelete(IResourceHashSet affected, ResourcePipeline pipeline) { return affected; } } public class DoubleDummyResourceDefinition2 : ResourceDefinition { diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreateTests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreateTests.cs index e3a775e536..0c29cc117a 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreateTests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreateTests.cs @@ -24,7 +24,7 @@ public void BeforeCreate() // act hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } @@ -43,7 +43,7 @@ public void BeforeCreate_Without_Parent_Hook_Implemented() // act hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Never()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Never()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } @@ -61,7 +61,7 @@ public void BeforeCreate_Without_Child_Hook_Implemented() // act hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } [Fact] diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs index 827901de63..a7289e1ece 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs @@ -54,7 +54,7 @@ public void BeforeCreate() hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), It.IsAny>(), @@ -101,7 +101,7 @@ public void BeforeCreate_Without_Child_Hook_Implemented() hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( It.Is>(rh => TodoCheckRelationships(rh, description + description)), ResourcePipeline.Post), @@ -122,7 +122,7 @@ public void BeforeCreate_NoImplicit() hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), It.IsAny>(), @@ -165,7 +165,7 @@ public void BeforeCreate_NoImplicit_Without_Child_Hook_Implemented() hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDeleteTests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDeleteTests.cs index 763d0716c4..4f6afa901e 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDeleteTests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDeleteTests.cs @@ -22,7 +22,7 @@ public void BeforeDelete() hookExecutor.BeforeDelete(todoList, ResourcePipeline.Delete); // assert - resourceDefinitionMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); + resourceDefinitionMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); resourceDefinitionMock.VerifyNoOtherCalls(); } diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDelete_WithDbValue_Tests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDelete_WithDbValue_Tests.cs index 88a2c0127d..70a76b0878 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDelete_WithDbValue_Tests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDelete_WithDbValue_Tests.cs @@ -47,7 +47,7 @@ public void BeforeDelete() hookExecutor.BeforeDelete(new List { person }, ResourcePipeline.Delete); // assert - personResourceMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); + personResourceMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship(It.Is>( rh => CheckImplicitTodos(rh) ), ResourcePipeline.Delete), Times.Once()); passportResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship(It.Is>( rh => CheckImplicitPassports(rh) ), ResourcePipeline.Delete), Times.Once()); VerifyNoOtherCalls(personResourceMock, todoResourceMock, passportResourceMock); @@ -88,7 +88,7 @@ public void BeforeDelete_No_Children_Hooks() hookExecutor.BeforeDelete(new List { person }, ResourcePipeline.Delete); // assert - personResourceMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); + personResourceMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); VerifyNoOtherCalls(personResourceMock, todoResourceMock, passportResourceMock); } diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdateTests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdateTests.cs index b5049b6fe6..5e3b622f39 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdateTests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdateTests.cs @@ -24,7 +24,7 @@ public void BeforeUpdate() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } @@ -62,7 +62,7 @@ public void BeforeUpdate_Without_Child_Hook_Implemented() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs index 2bbc977d62..33ada81370 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs @@ -59,7 +59,7 @@ public void BeforeUpdate() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), It.Is>(rh => PersonCheck(lastName, rh)), @@ -93,7 +93,7 @@ public void BeforeUpdate_Deleting_Relationship() hookExecutor.BeforeUpdate(_todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( It.Is>(rh => PersonCheck(lastName + lastName, rh)), ResourcePipeline.Patch), @@ -140,7 +140,7 @@ public void BeforeUpdate_Without_Child_Hook_Implemented() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( It.Is>(rh => TodoCheck(rh, description + description)), ResourcePipeline.Patch), @@ -161,7 +161,7 @@ public void BeforeUpdate_NoImplicit() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), It.IsAny>(), @@ -204,11 +204,11 @@ public void BeforeUpdate_NoImplicit_Without_Child_Hook_Implemented() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } - private bool TodoCheck(IAffectedResourcesDiffs diff, string checksum) + private bool TodoCheck(IResourceDiffs diff, string checksum) { var diffPair = diff.Single(); var dbCheck = diffPair.DatabaseValue.Description == checksum; diff --git a/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs b/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs index 648bf5a8e4..56fae91450 100644 --- a/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs +++ b/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs @@ -254,18 +254,18 @@ protected DbContextOptions InitInMemoryDb(Action seeder void MockHooks(Mock> resourceDefinition) where TModel : class, IIdentifiable { resourceDefinition - .Setup(rd => rd.BeforeCreate(It.IsAny>(), It.IsAny())) + .Setup(rd => rd.BeforeCreate(It.IsAny>(), It.IsAny())) .Returns, ResourcePipeline>((entities, context) => entities) .Verifiable(); resourceDefinition .Setup(rd => rd.BeforeRead(It.IsAny(), It.IsAny(), It.IsAny())) .Verifiable(); resourceDefinition - .Setup(rd => rd.BeforeUpdate(It.IsAny>(), It.IsAny())) - .Returns, ResourcePipeline>((entityDiff, context) => entityDiff.Resources) + .Setup(rd => rd.BeforeUpdate(It.IsAny>(), It.IsAny())) + .Returns, ResourcePipeline>((entityDiff, context) => entityDiff.Resources) .Verifiable(); resourceDefinition - .Setup(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny())) + .Setup(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny())) .Returns, ResourcePipeline>((entities, context) => entities) .Verifiable(); resourceDefinition From 9ab7b3588dae64289c351b39f4f8c7f910496027 Mon Sep 17 00:00:00 2001 From: Maurits Moeys Date: Fri, 21 Jun 2019 12:22:27 +0200 Subject: [PATCH 10/10] chore: renamed type parameters for consistency --- JsonApiDotnetCore.sln | 2 +- .../Resources/TagResource.cs | 2 +- .../{ResourceDiffs.cs => EntityDiffs.cs} | 58 +++++++------- .../{ResourceHashSet.cs => EntityHashSet.cs} | 12 +-- .../Hooks/IResourceHookContainer.cs | 75 +++++++++---------- .../Hooks/IResourceHookExecutor.cs | 50 ++++++------- .../Hooks/ResourceHookExecutor.cs | 6 +- .../Models/ResourceDefinition.cs | 6 +- .../Data/DefaultEntityRepository_Tests.cs | 1 - .../UnitTests/ResourceHooks/DiscoveryTests.cs | 9 +-- .../Create/BeforeCreateTests.cs | 6 +- .../Create/BeforeCreate_WithDbValues_Tests.cs | 8 +- .../Delete/BeforeDeleteTests.cs | 2 +- .../Delete/BeforeDelete_WithDbValue_Tests.cs | 4 +- .../Update/BeforeUpdateTests.cs | 4 +- .../Update/BeforeUpdate_WithDbValues_Tests.cs | 14 ++-- .../ResourceHooks/ResourceHooksTestsSetup.cs | 8 +- 17 files changed, 127 insertions(+), 140 deletions(-) rename src/JsonApiDotNetCore/Hooks/Execution/{ResourceDiffs.cs => EntityDiffs.cs} (55%) rename src/JsonApiDotNetCore/Hooks/Execution/{ResourceHashSet.cs => EntityHashSet.cs} (82%) diff --git a/JsonApiDotnetCore.sln b/JsonApiDotnetCore.sln index 76349968a2..a0330ce005 100644 --- a/JsonApiDotnetCore.sln +++ b/JsonApiDotnetCore.sln @@ -10,7 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{7A2B7ADD-ECB EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{24B15015-62E5-42E1-9BA0-ECE6BE7AA15F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonApiDotNetCoreExampleTests", "test\JsonApiDotNetCoreExampleTests\JsonApiDotNetCoreExampleTests.csproj", "{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonApiDotNetCoreExampleTests", "test\JsonApiDotNetCoreExampleTests\JsonApiDotNetCoreExampleTests.csproj", "{0B959765-40D2-43B5-87EE-FE2FEF9DBED5}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C5B4D998-CECB-454D-9F32-085A897577BE}" ProjectSection(SolutionItems) = preProject diff --git a/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs b/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs index e12e04a297..e3b3100ddd 100644 --- a/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs +++ b/src/Examples/JsonApiDotNetCoreExample/Resources/TagResource.cs @@ -13,7 +13,7 @@ public TagResource(IResourceGraph graph) : base(graph) { } - public override IEnumerable BeforeCreate(IResourceHashSet affected, ResourcePipeline pipeline) + public override IEnumerable BeforeCreate(IEntityHashSet affected, ResourcePipeline pipeline) { return base.BeforeCreate(affected, pipeline); } diff --git a/src/JsonApiDotNetCore/Hooks/Execution/ResourceDiffs.cs b/src/JsonApiDotNetCore/Hooks/Execution/EntityDiffs.cs similarity index 55% rename from src/JsonApiDotNetCore/Hooks/Execution/ResourceDiffs.cs rename to src/JsonApiDotNetCore/Hooks/Execution/EntityDiffs.cs index b7d1a05550..f0379636b5 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/ResourceDiffs.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/EntityDiffs.cs @@ -12,40 +12,40 @@ namespace JsonApiDotNetCore.Hooks /// Contains the resources from the request and the corresponding database values. /// /// Also contains information about updated relationships through - /// implementation of IRelationshipsDictionary> + /// implementation of IRelationshipsDictionary> /// - public interface IResourceDiffs : IRelationshipsDictionary, IEnumerable> where TResource : class, IIdentifiable + public interface IEntityDiff : IRelationshipsDictionary, IEnumerable> where TEntity : class, IIdentifiable { /// /// The database values of the resources affected by the request. /// - HashSet DatabaseValues { get; } + HashSet DatabaseValues { get; } /// /// The resources that were affected by the request. /// - HashSet Resources { get; } + HashSet Entities { get; } } /// - public class ResourceDiffs : IResourceDiffs where TResource : class, IIdentifiable + public class EntityDiffs : IEntityDiff where TEntity : class, IIdentifiable { /// - public HashSet DatabaseValues { get => _databaseValues ?? ThrowNoDbValuesError(); } - private readonly HashSet _databaseValues; + public HashSet DatabaseValues { get => _databaseValues ?? ThrowNoDbValuesError(); } + private readonly HashSet _databaseValues; private readonly bool _databaseValuesLoaded; /// - public HashSet Resources { get; private set; } + public HashSet Entities { get; private set; } /// - public RelationshipsDictionary AffectedRelationships { get; private set; } + public RelationshipsDictionary AffectedRelationships { get; private set; } - public ResourceDiffs(HashSet requestEntities, - HashSet databaseEntities, - Dictionary> relationships) + public EntityDiffs(HashSet requestEntities, + HashSet databaseEntities, + Dictionary> relationships) { - Resources = requestEntities; - AffectedRelationships = new RelationshipsDictionary(relationships); + Entities = requestEntities; + AffectedRelationships = new RelationshipsDictionary(relationships); _databaseValues = databaseEntities; _databaseValuesLoaded |= _databaseValues != null; } @@ -53,65 +53,65 @@ public ResourceDiffs(HashSet requestEntities, /// /// Used internally by the ResourceHookExecutor to make live a bit easier with generics /// - internal ResourceDiffs(IEnumerable requestEntities, + internal EntityDiffs(IEnumerable requestEntities, IEnumerable databaseEntities, Dictionary relationships) - : this((HashSet)requestEntities, (HashSet)databaseEntities, TypeHelper.ConvertRelationshipDictionary(relationships)) { } + : this((HashSet)requestEntities, (HashSet)databaseEntities, TypeHelper.ConvertRelationshipDictionary(relationships)) { } /// - public Dictionary> GetByRelationship() where TPrincipalResource : class, IIdentifiable + public Dictionary> GetByRelationship() where TPrincipalResource : class, IIdentifiable { return GetByRelationship(typeof(TPrincipalResource)); } /// - public Dictionary> GetByRelationship(Type principalType) + public Dictionary> GetByRelationship(Type principalType) { return AffectedRelationships.GetByRelationship(principalType); } /// - public IEnumerator> GetEnumerator() + public IEnumerator> GetEnumerator() { if (!_databaseValuesLoaded) ThrowNoDbValuesError(); - foreach (var entity in Resources) + foreach (var entity in Entities) { - TResource currentValueInDatabase = null; + TEntity currentValueInDatabase = null; currentValueInDatabase = _databaseValues.Single(e => entity.StringId == e.StringId); - yield return new ResourceDiffPair(entity, currentValueInDatabase); + yield return new EntityDiffPair(entity, currentValueInDatabase); } } /// IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - private HashSet ThrowNoDbValuesError() + private HashSet ThrowNoDbValuesError() { throw new MemberAccessException("Cannot access database entities if the LoadDatabaseValues option is set to false"); } } /// - /// A wrapper that contains an resource that is affected by the request, + /// A wrapper that contains an entity that is affected by the request, /// matched to its current database value /// - public class ResourceDiffPair where TResource : class, IIdentifiable + public class EntityDiffPair where TEntity : class, IIdentifiable { - public ResourceDiffPair(TResource resource, TResource databaseValue) + public EntityDiffPair(TEntity entity, TEntity databaseValue) { - Resource = resource; + Entity = entity; DatabaseValue = databaseValue; } /// /// The resource from the request matching the resource from the database. /// - public TResource Resource { get; private set; } + public TEntity Entity { get; private set; } /// /// The resource from the database matching the resource from the request. /// - public TResource DatabaseValue { get; private set; } + public TEntity DatabaseValue { get; private set; } } } diff --git a/src/JsonApiDotNetCore/Hooks/Execution/ResourceHashSet.cs b/src/JsonApiDotNetCore/Hooks/Execution/EntityHashSet.cs similarity index 82% rename from src/JsonApiDotNetCore/Hooks/Execution/ResourceHashSet.cs rename to src/JsonApiDotNetCore/Hooks/Execution/EntityHashSet.cs index 7fb83f3666..98d7393796 100644 --- a/src/JsonApiDotNetCore/Hooks/Execution/ResourceHashSet.cs +++ b/src/JsonApiDotNetCore/Hooks/Execution/EntityHashSet.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using JsonApiDotNetCore.Models; -using System.Linq; using System.Collections; using JsonApiDotNetCore.Internal; using System; @@ -13,10 +12,7 @@ namespace JsonApiDotNetCore.Hooks /// Also contains information about updated relationships through /// implementation of IAffectedRelationshipsDictionary> /// - public interface IResourceHashSet : IRelationshipsDictionary, IEnumerable where TResource : class, IIdentifiable - { - - } + public interface IEntityHashSet : IRelationshipsDictionary, IEnumerable where TResource : class, IIdentifiable { } /// /// Implementation of IResourceHashSet{TResource}. @@ -26,12 +22,12 @@ public interface IResourceHashSet : IRelationshipsDictionary> /// - public class ResourceHashSet : HashSet, IResourceHashSet where TResource : class, IIdentifiable + public class EntityHashSet : HashSet, IEntityHashSet where TResource : class, IIdentifiable { /// public RelationshipsDictionary AffectedRelationships { get; private set; } - public ResourceHashSet(HashSet entities, + public EntityHashSet(HashSet entities, Dictionary> relationships) : base(entities) { AffectedRelationships = new RelationshipsDictionary(relationships); @@ -40,7 +36,7 @@ public ResourceHashSet(HashSet entities, /// /// Used internally by the ResourceHookExecutor to make live a bit easier with generics /// - internal ResourceHashSet(IEnumerable entities, + internal EntityHashSet(IEnumerable entities, Dictionary relationships) : this((HashSet)entities, TypeHelper.ConvertRelationshipDictionary(relationships)) { } diff --git a/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs b/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs index 139e3ca392..cadb96a4fa 100644 --- a/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs +++ b/src/JsonApiDotNetCore/Hooks/IResourceHookContainer.cs @@ -12,17 +12,16 @@ public interface IResourceHookContainer { } /// /// Implement this interface to implement business logic hooks on . /// - public interface IResourceHookContainer : IBeforeHooks, IAfterHooks, IOnHooks, IResourceHookContainer where TEntity : class, IIdentifiable { } - + public interface IResourceHookContainer : IBeforeHooks, IAfterHooks, IOnHooks, IResourceHookContainer where TResource : class, IIdentifiable { } /// /// Wrapper interface for all Before hooks. /// - public interface IBeforeHooks where TEntity : class, IIdentifiable + public interface IBeforeHooks where TResource : class, IIdentifiable { /// /// Implement this hook to run custom logic in the - /// layer just before creation of entities of type . + /// layer just before creation of entities of type . /// /// For the pipeline, /// will typically contain one entry. For , @@ -41,10 +40,10 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// The transformed entity set /// The unique set of affected entities. /// An enum indicating from where the hook was triggered. - IEnumerable BeforeCreate(IResourceHashSet entities, ResourcePipeline pipeline); + IEnumerable BeforeCreate(IEntityHashSet entities, ResourcePipeline pipeline); /// /// Implement this hook to run custom logic in the - /// layer just before reading entities of type . + /// layer just before reading entities of type . /// /// An enum indicating from where the hook was triggered. /// Indicates whether the to be queried entities are the main request entities or if they were included @@ -52,15 +51,15 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable void BeforeRead(ResourcePipeline pipeline, bool isIncluded = false, string stringId = null); /// /// Implement this hook to run custom logic in the - /// layer just before updating entities of type . + /// layer just before updating entities of type . /// /// For the pipeline, the - /// will typically contain one entity. + /// will typically contain one entity. /// For , this it may contain /// multiple entities. /// /// The returned may be a subset - /// of the property in parameter , + /// of the property in parameter , /// in which case the operation of the pipeline will not be executed /// for the omitted entities. The returned set may also contain custom /// changes of the properties on the entities. @@ -76,13 +75,13 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// hook is fired for these. /// /// The transformed entity set - /// The entity diff. + /// The entity diff. /// An enum indicating from where the hook was triggered. - IEnumerable BeforeUpdate(IResourceDiffs ResourceDiff, ResourcePipeline pipeline); + IEnumerable BeforeUpdate(IEntityDiff entityDiff, ResourcePipeline pipeline); /// /// Implement this hook to run custom logic in the - /// layer just before deleting entities of type . + /// layer just before deleting entities of type . /// /// For the pipeline, /// will typically contain one entity. @@ -101,13 +100,13 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// The transformed entity set /// The unique set of affected entities. /// An enum indicating from where the hook was triggered. - IEnumerable BeforeDelete(IResourceHashSet entities, ResourcePipeline pipeline); + IEnumerable BeforeDelete(IEntityHashSet entities, ResourcePipeline pipeline); /// /// Implement this hook to run custom logic in the - /// layer just before updating relationships to entities of type . + /// layer just before updating relationships to entities of type . /// /// This hook is fired when a relationship is created to entities of type - /// from a dependent pipeline ( + /// from a dependent pipeline ( /// or ). For example, If an Article was created /// and its author relationship was set to an existing Person, this hook will be fired /// for that particular Person. @@ -120,14 +119,14 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// The transformed set of ids /// The unique set of ids /// An enum indicating from where the hook was triggered. - /// A helper that groups the entities by the affected relationship - IEnumerable BeforeUpdateRelationship(HashSet ids, IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline); + /// A helper that groups the entities by the affected relationship + IEnumerable BeforeUpdateRelationship(HashSet ids, IRelationshipsDictionary entitiesByRelationship, ResourcePipeline pipeline); /// /// Implement this hook to run custom logic in the - /// layer just before implicitly updating relationships to entities of type . + /// layer just before implicitly updating relationships to entities of type . /// /// This hook is fired when a relationship to entities of type - /// is implicitly affected from a dependent pipeline ( + /// is implicitly affected from a dependent pipeline ( /// or ). For example, if an Article was updated /// by setting its author relationship (one-to-one) to an existing Person, /// and by this the relationship to a different Person was implicitly removed, @@ -138,25 +137,19 @@ public interface IBeforeHooks where TEntity : class, IIdentifiable /// /// /// The transformed set of ids - /// A helper that groups the entities by the affected relationship + /// A helper that groups the entities by the affected relationship /// An enum indicating from where the hook was triggered. - void BeforeImplicitUpdateRelationship(IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline); + void BeforeImplicitUpdateRelationship(IRelationshipsDictionary entitiesByRelationship, ResourcePipeline pipeline); } - - - - - - /// /// Wrapper interface for all After hooks. /// - public interface IAfterHooks where TEntity : class, IIdentifiable + public interface IAfterHooks where TResource : class, IIdentifiable { /// /// Implement this hook to run custom logic in the - /// layer just after creation of entities of type . + /// layer just after creation of entities of type . /// /// If relationships were created with the created entities, this will /// be reflected by the corresponding NavigationProperty being set. @@ -166,19 +159,19 @@ public interface IAfterHooks where TEntity : class, IIdentifiable /// The transformed entity set /// The unique set of affected entities. /// An enum indicating from where the hook was triggered. - void AfterCreate(HashSet entities, ResourcePipeline pipeline); + void AfterCreate(HashSet entities, ResourcePipeline pipeline); /// /// Implement this hook to run custom logic in the - /// layer just after reading entities of type . + /// layer just after reading entities of type . /// /// The unique set of affected entities. /// An enum indicating from where the hook was triggered. /// A boolean to indicate whether the entities in this hook execution are the main entities of the request, /// or if they were included as a relationship - void AfterRead(HashSet entities, ResourcePipeline pipeline, bool isIncluded = false); + void AfterRead(HashSet entities, ResourcePipeline pipeline, bool isIncluded = false); /// /// Implement this hook to run custom logic in the - /// layer just after updating entities of type . + /// layer just after updating entities of type . /// /// If relationships were updated with the updated entities, this will /// be reflected by the corresponding NavigationProperty being set. @@ -187,32 +180,32 @@ public interface IAfterHooks where TEntity : class, IIdentifiable /// /// The unique set of affected entities. /// An enum indicating from where the hook was triggered. - void AfterUpdate(HashSet entities, ResourcePipeline pipeline); + void AfterUpdate(HashSet entities, ResourcePipeline pipeline); /// /// Implement this hook to run custom logic in the - /// layer just after deletion of entities of type . + /// layer just after deletion of entities of type . /// /// The unique set of affected entities. /// An enum indicating from where the hook was triggered. /// If set to true if the deletion was succeeded in the repository layer. - void AfterDelete(HashSet entities, ResourcePipeline pipeline, bool succeeded); + void AfterDelete(HashSet entities, ResourcePipeline pipeline, bool succeeded); /// /// Implement this hook to run custom logic in the layer /// just after a relationship was updated. /// - /// Relationship helper. + /// Relationship helper. /// An enum indicating from where the hook was triggered. - void AfterUpdateRelationship(IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline); + void AfterUpdateRelationship(IRelationshipsDictionary entitiesByRelationship, ResourcePipeline pipeline); } /// /// Wrapper interface for all on hooks. /// - public interface IOnHooks where TEntity : class, IIdentifiable + public interface IOnHooks where TResource : class, IIdentifiable { /// /// Implement this hook to transform the result data just before returning - /// the entities of type from the + /// the entities of type from the /// layer /// /// The returned may be a subset @@ -223,6 +216,6 @@ public interface IOnHooks where TEntity : class, IIdentifiable /// The transformed entity set /// The unique set of affected entities /// An enum indicating from where the hook was triggered. - IEnumerable OnReturn(HashSet entities, ResourcePipeline pipeline); + IEnumerable OnReturn(HashSet entities, ResourcePipeline pipeline); } } diff --git a/src/JsonApiDotNetCore/Hooks/IResourceHookExecutor.cs b/src/JsonApiDotNetCore/Hooks/IResourceHookExecutor.cs index 75c2a35f2e..2d4f1fbdb7 100644 --- a/src/JsonApiDotNetCore/Hooks/IResourceHookExecutor.cs +++ b/src/JsonApiDotNetCore/Hooks/IResourceHookExecutor.cs @@ -26,7 +26,7 @@ public interface IBeforeExecutor /// The returned set will be used in the actual operation in . /// /// Fires the - /// hook where T = for values in parameter . + /// hook where T = for values in parameter . /// /// Fires the /// hook for any related (nested) entity for values within parameter @@ -34,26 +34,26 @@ public interface IBeforeExecutor /// The transformed set /// Target entities for the Before cycle. /// An enum indicating from where the hook was triggered. - /// The type of the root entities - IEnumerable BeforeCreate(IEnumerable entities, ResourcePipeline pipeline) where TEntity : class, IIdentifiable; + /// The type of the root entities + IEnumerable BeforeCreate(IEnumerable entities, ResourcePipeline pipeline) where TResource : class, IIdentifiable; /// /// Executes the Before Cycle by firing the appropiate hooks if they are implemented. /// /// Fires the - /// hook where T = for the requested + /// hook where T = for the requested /// entities as well as any related relationship. /// /// An enum indicating from where the hook was triggered. /// StringId of the requested entity in the case of /// . - /// The type of the request entity - void BeforeRead(ResourcePipeline pipeline, string stringId = null) where TEntity : class, IIdentifiable; + /// The type of the request entity + void BeforeRead(ResourcePipeline pipeline, string stringId = null) where TResource : class, IIdentifiable; /// /// Executes the Before Cycle by firing the appropiate hooks if they are implemented. /// The returned set will be used in the actual operation in . /// /// Fires the - /// hook where T = for values in parameter . + /// hook where T = for values in parameter . /// /// Fires the /// hook for any related (nested) entity for values within parameter @@ -67,14 +67,14 @@ public interface IBeforeExecutor /// The transformed set /// Target entities for the Before cycle. /// An enum indicating from where the hook was triggered. - /// The type of the root entities - IEnumerable BeforeUpdate(IEnumerable entities, ResourcePipeline pipeline) where TEntity : class, IIdentifiable; + /// The type of the root entities + IEnumerable BeforeUpdate(IEnumerable entities, ResourcePipeline pipeline) where TResource : class, IIdentifiable; /// /// Executes the Before Cycle by firing the appropiate hooks if they are implemented. /// The returned set will be used in the actual operation in . /// /// Fires the - /// hook where T = for values in parameter . + /// hook where T = for values in parameter . /// /// Fires the /// hook for any entities that are indirectly (implicitly) affected by this operation. @@ -84,8 +84,8 @@ public interface IBeforeExecutor /// The transformed set /// Target entities for the Before cycle. /// An enum indicating from where the hook was triggered. - /// The type of the root entities - IEnumerable BeforeDelete(IEnumerable entities, ResourcePipeline pipeline) where TEntity : class, IIdentifiable; + /// The type of the root entities + IEnumerable BeforeDelete(IEnumerable entities, ResourcePipeline pipeline) where TResource : class, IIdentifiable; } /// @@ -97,15 +97,15 @@ public interface IAfterExecutor /// Executes the After Cycle by firing the appropiate hooks if they are implemented. /// /// Fires the - /// hook where T = for values in parameter . + /// hook where T = for values in parameter . /// /// Fires the /// hook for any related (nested) entity for values within parameter /// /// Target entities for the Before cycle. /// An enum indicating from where the hook was triggered. - /// The type of the root entities - void AfterCreate(IEnumerable entities, ResourcePipeline pipeline) where TEntity : class, IIdentifiable; + /// The type of the root entities + void AfterCreate(IEnumerable entities, ResourcePipeline pipeline) where TResource : class, IIdentifiable; /// /// Executes the After Cycle by firing the appropiate hooks if they are implemented. /// @@ -114,31 +114,31 @@ public interface IAfterExecutor /// /// Target entities for the Before cycle. /// An enum indicating from where the hook was triggered. - /// The type of the root entities - void AfterRead(IEnumerable entities, ResourcePipeline pipeline) where TEntity : class, IIdentifiable; + /// The type of the root entities + void AfterRead(IEnumerable entities, ResourcePipeline pipeline) where TResource : class, IIdentifiable; /// /// Executes the After Cycle by firing the appropiate hooks if they are implemented. /// /// Fires the - /// hook where T = for values in parameter . + /// hook where T = for values in parameter . /// /// Fires the /// hook for any related (nested) entity for values within parameter /// /// Target entities for the Before cycle. /// An enum indicating from where the hook was triggered. - /// The type of the root entities - void AfterUpdate(IEnumerable entities, ResourcePipeline pipeline) where TEntity : class, IIdentifiable; + /// The type of the root entities + void AfterUpdate(IEnumerable entities, ResourcePipeline pipeline) where TResource : class, IIdentifiable; /// /// Executes the After Cycle by firing the appropiate hooks if they are implemented. /// /// Fires the - /// hook where T = for values in parameter . + /// hook where T = for values in parameter . /// /// Target entities for the Before cycle. /// An enum indicating from where the hook was triggered. - /// The type of the root entities - void AfterDelete(IEnumerable entities, ResourcePipeline pipeline, bool succeeded) where TEntity : class, IIdentifiable; + /// The type of the root entities + void AfterDelete(IEnumerable entities, ResourcePipeline pipeline, bool succeeded) where TResource : class, IIdentifiable; } /// @@ -155,7 +155,7 @@ public interface IOnExecutor /// The transformed set /// Target entities for the Before cycle. /// An enum indicating from where the hook was triggered. - /// The type of the root entities - IEnumerable OnReturn(IEnumerable entities, ResourcePipeline pipeline) where TEntity : class, IIdentifiable; + /// The type of the root entities + IEnumerable OnReturn(IEnumerable entities, ResourcePipeline pipeline) where TResource : class, IIdentifiable; } } \ No newline at end of file diff --git a/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs b/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs index 5591b397be..7fccbbba7f 100644 --- a/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs +++ b/src/JsonApiDotNetCore/Hooks/ResourceHookExecutor.cs @@ -49,7 +49,7 @@ public virtual IEnumerable BeforeUpdate(IEnumerable e { var relationships = node.RelationshipsToNextLayer.Select(p => p.Attribute).ToArray(); var dbValues = LoadDbValues(typeof(TEntity), (IEnumerable)node.UniqueEntities, ResourceHook.BeforeUpdate, relationships); - var diff = new ResourceDiffs(node.UniqueEntities, dbValues, node.PrincipalsToNextLayer()); + var diff = new EntityDiffs(node.UniqueEntities, dbValues, node.PrincipalsToNextLayer()); IEnumerable updated = container.BeforeUpdate(diff, pipeline); node.UpdateUnique(updated); node.Reassign(entities); @@ -65,7 +65,7 @@ public virtual IEnumerable BeforeCreate(IEnumerable e { if (GetHook(ResourceHook.BeforeCreate, entities, out var container, out var node)) { - var affected = new ResourceHashSet((HashSet)node.UniqueEntities, node.PrincipalsToNextLayer()); + var affected = new EntityHashSet((HashSet)node.UniqueEntities, node.PrincipalsToNextLayer()); IEnumerable updated = container.BeforeCreate(affected, pipeline); node.UpdateUnique(updated); node.Reassign(entities); @@ -82,7 +82,7 @@ public virtual IEnumerable BeforeDelete(IEnumerable e { var relationships = node.RelationshipsToNextLayer.Select(p => p.Attribute).ToArray(); var targetEntities = LoadDbValues(typeof(TEntity), (IEnumerable)node.UniqueEntities, ResourceHook.BeforeDelete, relationships) ?? node.UniqueEntities; - var affected = new ResourceHashSet(targetEntities, node.PrincipalsToNextLayer()); + var affected = new EntityHashSet(targetEntities, node.PrincipalsToNextLayer()); IEnumerable updated = container.BeforeDelete(affected, pipeline); node.UpdateUnique(updated); diff --git a/src/JsonApiDotNetCore/Models/ResourceDefinition.cs b/src/JsonApiDotNetCore/Models/ResourceDefinition.cs index a4420465ed..e615de6538 100644 --- a/src/JsonApiDotNetCore/Models/ResourceDefinition.cs +++ b/src/JsonApiDotNetCore/Models/ResourceDefinition.cs @@ -175,13 +175,13 @@ public virtual void AfterDelete(HashSet entities, ResourcePipeline pipeline, /// public virtual void AfterUpdateRelationship(IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline) { } /// - public virtual IEnumerable BeforeCreate(IResourceHashSet affected, ResourcePipeline pipeline) { return affected; } + public virtual IEnumerable BeforeCreate(IEntityHashSet affected, ResourcePipeline pipeline) { return affected; } /// public virtual void BeforeRead(ResourcePipeline pipeline, bool isIncluded = false, string stringId = null) { } /// - public virtual IEnumerable BeforeUpdate(IResourceDiffs ResourceDiff, ResourcePipeline pipeline) { return ResourceDiff.Resources; } + public virtual IEnumerable BeforeUpdate(IEntityDiff ResourceDiff, ResourcePipeline pipeline) { return ResourceDiff.Entities; } /// - public virtual IEnumerable BeforeDelete(IResourceHashSet affected, ResourcePipeline pipeline) { return affected; } + public virtual IEnumerable BeforeDelete(IEntityHashSet affected, ResourcePipeline pipeline) { return affected; } /// public virtual IEnumerable BeforeUpdateRelationship(HashSet ids, IRelationshipsDictionary resourcesByRelationship, ResourcePipeline pipeline) { return ids; } /// diff --git a/test/UnitTests/Data/DefaultEntityRepository_Tests.cs b/test/UnitTests/Data/DefaultEntityRepository_Tests.cs index 14116bb574..97cf51d587 100644 --- a/test/UnitTests/Data/DefaultEntityRepository_Tests.cs +++ b/test/UnitTests/Data/DefaultEntityRepository_Tests.cs @@ -12,7 +12,6 @@ using JsonApiDotNetCore.Services; using System.Threading.Tasks; using System.Linq; -using System.Collections; using JsonApiDotNetCore.Request; namespace UnitTests.Data diff --git a/test/UnitTests/ResourceHooks/DiscoveryTests.cs b/test/UnitTests/ResourceHooks/DiscoveryTests.cs index 8c8c4a7f4b..bde024f530 100644 --- a/test/UnitTests/ResourceHooks/DiscoveryTests.cs +++ b/test/UnitTests/ResourceHooks/DiscoveryTests.cs @@ -14,7 +14,7 @@ public class DummyResourceDefinition : ResourceDefinition { public DummyResourceDefinition() : base(new ResourceGraphBuilder().AddResource().Build()) { } - public override IEnumerable BeforeDelete(IResourceHashSet affected, ResourcePipeline pipeline) { return affected; } + public override IEnumerable BeforeDelete(IEntityHashSet affected, ResourcePipeline pipeline) { return affected; } public override void AfterDelete(HashSet entities, ResourcePipeline pipeline, bool succeeded) { } } @@ -29,13 +29,12 @@ public void Hook_Discovery() } - public class AnotherDummy : Identifiable { } public abstract class ResourceDefintionBase : ResourceDefinition where T : class, IIdentifiable { protected ResourceDefintionBase(IResourceGraph graph) : base(graph) { } - public override IEnumerable BeforeDelete(IResourceHashSet affected, ResourcePipeline pipeline) { return affected; } + public override IEnumerable BeforeDelete(IEntityHashSet affected, ResourcePipeline pipeline) { return affected; } public override void AfterDelete(HashSet entities, ResourcePipeline pipeline, bool succeeded) { } } @@ -59,7 +58,7 @@ public class YetAnotherDummyResourceDefinition : ResourceDefinition().Build()) { } - public override IEnumerable BeforeDelete(IResourceHashSet affected, ResourcePipeline pipeline) { return affected; } + public override IEnumerable BeforeDelete(IEntityHashSet affected, ResourcePipeline pipeline) { return affected; } [LoadDatabaseValues(false)] public override void AfterDelete(HashSet entities, ResourcePipeline pipeline, bool succeeded) { } @@ -81,7 +80,7 @@ public class DoubleDummyResourceDefinition1 : ResourceDefinition { public DoubleDummyResourceDefinition1() : base(new ResourceGraphBuilder().AddResource().Build()) { } - public override IEnumerable BeforeDelete(IResourceHashSet affected, ResourcePipeline pipeline) { return affected; } + public override IEnumerable BeforeDelete(IEntityHashSet affected, ResourcePipeline pipeline) { return affected; } } public class DoubleDummyResourceDefinition2 : ResourceDefinition { diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreateTests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreateTests.cs index 0c29cc117a..bc2163df2f 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreateTests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreateTests.cs @@ -24,7 +24,7 @@ public void BeforeCreate() // act hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } @@ -43,7 +43,7 @@ public void BeforeCreate_Without_Parent_Hook_Implemented() // act hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Never()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Never()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } @@ -61,7 +61,7 @@ public void BeforeCreate_Without_Child_Hook_Implemented() // act hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.IsAny>(), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } [Fact] diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs index a7289e1ece..c574de145c 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Create/BeforeCreate_WithDbValues_Tests.cs @@ -54,7 +54,7 @@ public void BeforeCreate() hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), It.IsAny>(), @@ -101,7 +101,7 @@ public void BeforeCreate_Without_Child_Hook_Implemented() hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( It.Is>(rh => TodoCheckRelationships(rh, description + description)), ResourcePipeline.Post), @@ -122,7 +122,7 @@ public void BeforeCreate_NoImplicit() hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), It.IsAny>(), @@ -165,7 +165,7 @@ public void BeforeCreate_NoImplicit_Without_Child_Hook_Implemented() hookExecutor.BeforeCreate(todoList, ResourcePipeline.Post); // assert - todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeCreate(It.Is>((entities) => TodoCheck(entities, description)), ResourcePipeline.Post), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDeleteTests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDeleteTests.cs index 4f6afa901e..887a322994 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDeleteTests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDeleteTests.cs @@ -22,7 +22,7 @@ public void BeforeDelete() hookExecutor.BeforeDelete(todoList, ResourcePipeline.Delete); // assert - resourceDefinitionMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); + resourceDefinitionMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); resourceDefinitionMock.VerifyNoOtherCalls(); } diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDelete_WithDbValue_Tests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDelete_WithDbValue_Tests.cs index 70a76b0878..f63adcbd6e 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDelete_WithDbValue_Tests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Delete/BeforeDelete_WithDbValue_Tests.cs @@ -47,7 +47,7 @@ public void BeforeDelete() hookExecutor.BeforeDelete(new List { person }, ResourcePipeline.Delete); // assert - personResourceMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); + personResourceMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship(It.Is>( rh => CheckImplicitTodos(rh) ), ResourcePipeline.Delete), Times.Once()); passportResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship(It.Is>( rh => CheckImplicitPassports(rh) ), ResourcePipeline.Delete), Times.Once()); VerifyNoOtherCalls(personResourceMock, todoResourceMock, passportResourceMock); @@ -88,7 +88,7 @@ public void BeforeDelete_No_Children_Hooks() hookExecutor.BeforeDelete(new List { person }, ResourcePipeline.Delete); // assert - personResourceMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); + personResourceMock.Verify(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny()), Times.Once()); VerifyNoOtherCalls(personResourceMock, todoResourceMock, passportResourceMock); } diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdateTests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdateTests.cs index 5e3b622f39..e27f7f8caa 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdateTests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdateTests.cs @@ -24,7 +24,7 @@ public void BeforeUpdate() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship(It.IsAny>(), It.IsAny>(), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } @@ -62,7 +62,7 @@ public void BeforeUpdate_Without_Child_Hook_Implemented() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.IsAny>(), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } diff --git a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs index 33ada81370..dd1eeea5e1 100644 --- a/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs +++ b/test/UnitTests/ResourceHooks/ResourceHookExecutor/Update/BeforeUpdate_WithDbValues_Tests.cs @@ -59,7 +59,7 @@ public void BeforeUpdate() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), It.Is>(rh => PersonCheck(lastName, rh)), @@ -93,7 +93,7 @@ public void BeforeUpdate_Deleting_Relationship() hookExecutor.BeforeUpdate(_todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( It.Is>(rh => PersonCheck(lastName + lastName, rh)), ResourcePipeline.Patch), @@ -140,7 +140,7 @@ public void BeforeUpdate_Without_Child_Hook_Implemented() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); todoResourceMock.Verify(rd => rd.BeforeImplicitUpdateRelationship( It.Is>(rh => TodoCheck(rh, description + description)), ResourcePipeline.Patch), @@ -161,7 +161,7 @@ public void BeforeUpdate_NoImplicit() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); ownerResourceMock.Verify(rd => rd.BeforeUpdateRelationship( It.Is>(ids => PersonIdCheck(ids, personId)), It.IsAny>(), @@ -204,15 +204,15 @@ public void BeforeUpdate_NoImplicit_Without_Child_Hook_Implemented() hookExecutor.BeforeUpdate(todoList, ResourcePipeline.Patch); // assert - todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); + todoResourceMock.Verify(rd => rd.BeforeUpdate(It.Is>((diff) => TodoCheck(diff, description)), ResourcePipeline.Patch), Times.Once()); VerifyNoOtherCalls(todoResourceMock, ownerResourceMock); } - private bool TodoCheck(IResourceDiffs diff, string checksum) + private bool TodoCheck(IEntityDiff diff, string checksum) { var diffPair = diff.Single(); var dbCheck = diffPair.DatabaseValue.Description == checksum; - var reqCheck = diffPair.Resource.Description == null; + var reqCheck = diffPair.Entity.Description == null; return (dbCheck && reqCheck); } diff --git a/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs b/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs index 56fae91450..369e46b26d 100644 --- a/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs +++ b/test/UnitTests/ResourceHooks/ResourceHooksTestsSetup.cs @@ -254,18 +254,18 @@ protected DbContextOptions InitInMemoryDb(Action seeder void MockHooks(Mock> resourceDefinition) where TModel : class, IIdentifiable { resourceDefinition - .Setup(rd => rd.BeforeCreate(It.IsAny>(), It.IsAny())) + .Setup(rd => rd.BeforeCreate(It.IsAny>(), It.IsAny())) .Returns, ResourcePipeline>((entities, context) => entities) .Verifiable(); resourceDefinition .Setup(rd => rd.BeforeRead(It.IsAny(), It.IsAny(), It.IsAny())) .Verifiable(); resourceDefinition - .Setup(rd => rd.BeforeUpdate(It.IsAny>(), It.IsAny())) - .Returns, ResourcePipeline>((entityDiff, context) => entityDiff.Resources) + .Setup(rd => rd.BeforeUpdate(It.IsAny>(), It.IsAny())) + .Returns, ResourcePipeline>((entityDiff, context) => entityDiff.Entities) .Verifiable(); resourceDefinition - .Setup(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny())) + .Setup(rd => rd.BeforeDelete(It.IsAny>(), It.IsAny())) .Returns, ResourcePipeline>((entities, context) => entities) .Verifiable(); resourceDefinition