Skip to content

Commit 9935a86

Browse files
committed
feat: relationshipdictionary now actually inherits from dictionary
1 parent 833d0e3 commit 9935a86

20 files changed

+167
-125
lines changed

src/Examples/JsonApiDotNetCoreExample/Resources/PassportResource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public override void BeforeRead(ResourcePipeline pipeline, bool isIncluded = fal
2222
}
2323
}
2424

25-
public override void BeforeImplicitUpdateRelationship(IAffectedRelationships<Passport> resourcesByRelationship, ResourcePipeline pipeline)
25+
public override void BeforeImplicitUpdateRelationship(IRelationshipsDictionary<Passport> resourcesByRelationship, ResourcePipeline pipeline)
2626
{
2727
resourcesByRelationship.GetByRelationship<Person>().ToList().ForEach(kvp => DoesNotTouchLockedPassports(kvp.Value));
2828
}

src/Examples/JsonApiDotNetCoreExample/Resources/PersonResource.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class PersonResource : LockableResourceBase<Person>
1010
{
1111
public PersonResource(IResourceGraph graph) : base(graph) { }
1212

13-
public override IEnumerable<string> BeforeUpdateRelationship(HashSet<string> ids, IAffectedRelationships<Person> resourcesByRelationship, ResourcePipeline pipeline)
13+
public override IEnumerable<string> BeforeUpdateRelationship(HashSet<string> ids, IRelationshipsDictionary<Person> resourcesByRelationship, ResourcePipeline pipeline)
1414
{
1515
BeforeImplicitUpdateRelationship(resourcesByRelationship, pipeline);
1616
return ids;
@@ -22,7 +22,7 @@ public override IEnumerable<string> BeforeUpdateRelationship(HashSet<string> ids
2222
// return entityDiff.Entities;
2323
//}
2424

25-
public override void BeforeImplicitUpdateRelationship(IAffectedRelationships<Person> resourcesByRelationship, ResourcePipeline pipeline)
25+
public override void BeforeImplicitUpdateRelationship(IRelationshipsDictionary<Person> resourcesByRelationship, ResourcePipeline pipeline)
2626
{
2727
resourcesByRelationship.GetByRelationship<Passport>().ToList().ForEach(kvp => DisallowLocked(kvp.Value));
2828
}

src/Examples/JsonApiDotNetCoreExample/Resources/TodoResource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public override void BeforeRead(ResourcePipeline pipeline, bool isIncluded = fal
1919
}
2020
}
2121

22-
public override void BeforeImplicitUpdateRelationship(IAffectedRelationships<TodoItem> resourcesByRelationship, ResourcePipeline pipeline)
22+
public override void BeforeImplicitUpdateRelationship(IRelationshipsDictionary<TodoItem> resourcesByRelationship, ResourcePipeline pipeline)
2323
{
2424
List<TodoItem> todos = resourcesByRelationship.GetByRelationship<Person>().SelectMany(kvp => kvp.Value).ToList();
2525
DisallowLocked(todos);

src/JsonApiDotNetCore/Hooks/Execution/AffectedResources.cs

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,56 @@
22
using JsonApiDotNetCore.Models;
33
using System.Linq;
44
using System.Collections;
5+
using JsonApiDotNetCore.Internal;
6+
using System;
57

68
namespace JsonApiDotNetCore.Hooks
79
{
810
/// <summary>
9-
/// Basically just a list of <typeparamref name="TResource"/>, but also contains information
10-
/// about updated relationships through inheritance of IAffectedRelationships<typeparamref name="TResource"/>>
11+
/// Basically a enumerable of <typeparamref name="TResource"/> of resources that were affected by the request.
12+
///
13+
/// Also contains information about updated relationships through
14+
/// implementation of IAffectedRelationshipsDictionary<typeparamref name="TResource"/>>
1115
/// </summary>
12-
public interface IAffectedResources<TResource> : IAffectedRelationships<TResource>, IEnumerable<TResource> where TResource : class, IIdentifiable
16+
public interface IAffectedResources<TResource> : IRelationshipsDictionary<TResource>, IEnumerable<TResource> where TResource : class, IIdentifiable
1317
{
14-
/// <summary>
15-
/// The entities that are affected by the request.
16-
/// </summary>
17-
HashSet<TResource> Resources { get; }
18+
1819
}
1920

20-
public class AffectedResources<TResource> : AffectedRelationships<TResource>, IAffectedResources<TResource> where TResource : class, IIdentifiable
21+
/// <summary>
22+
/// Implementation of IAffectedResources{TResource}.
23+
///
24+
/// It is basically just a HashSet{TResource} that also stores the
25+
/// RelationshipDictionary{TResource} and the same helper methods to access this
26+
/// dictionary as defined on IAffectedRelationshipsDictionary{TResource}.
27+
/// </summary>
28+
public class AffectedResources<TResource> : HashSet<TResource>, IAffectedResources<TResource> where TResource : class, IIdentifiable
2129
{
2230
/// <inheritdoc />
23-
public HashSet<TResource> Resources { get; }
31+
public RelationshipsDictionary<TResource> AffectedRelationships { get; private set; }
2432

2533
public AffectedResources(HashSet<TResource> entities,
26-
Dictionary<RelationshipAttribute, HashSet<TResource>> relationships) : base(relationships)
34+
Dictionary<RelationshipAttribute, HashSet<TResource>> relationships) : base(entities)
2735
{
28-
Resources = new HashSet<TResource>(entities.Cast<TResource>());
36+
AffectedRelationships = new RelationshipsDictionary<TResource>(relationships);
2937
}
3038

3139
/// <summary>
3240
/// Used internally by the ResourceHookExecutor to make live a bit easier with generics
3341
/// </summary>
3442
internal AffectedResources(IEnumerable entities,
3543
Dictionary<RelationshipAttribute, IEnumerable> relationships)
36-
: this((HashSet<TResource>)entities, ConvertRelationshipDictionary(relationships)) { }
44+
: this((HashSet<TResource>)entities, TypeHelper.ConvertRelationshipDictionary<TResource>(relationships)) { }
3745

38-
/// <inheritdoc />
39-
public IEnumerator<TResource> GetEnumerator()
46+
47+
public Dictionary<RelationshipAttribute, HashSet<TResource>> GetByRelationship(Type principalType)
4048
{
41-
return Resources.GetEnumerator();
49+
return AffectedRelationships.GetByRelationship(principalType);
4250
}
4351

44-
/// <inheritdoc />
45-
IEnumerator IEnumerable.GetEnumerator()
52+
public Dictionary<RelationshipAttribute, HashSet<TResource>> GetByRelationship<TPrincipalResource>() where TPrincipalResource : class, IIdentifiable
4653
{
47-
return GetEnumerator();
54+
return GetByRelationship<TPrincipalResource>();
4855
}
4956
}
5057
}

src/JsonApiDotNetCore/Hooks/Execution/AffectedResourceDiff.cs renamed to src/JsonApiDotNetCore/Hooks/Execution/AffectedResourcesDiffs.cs

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,77 @@
22
using System.Collections;
33
using System.Collections.Generic;
44
using System.Linq;
5+
using JsonApiDotNetCore.Internal;
56
using JsonApiDotNetCore.Models;
67

78
namespace JsonApiDotNetCore.Hooks
89
{
910
/// <summary>
10-
/// A helper class that provides insight in what is to be updated. The
11-
/// <see cref="IAffectedResourcesDiff{TEntity}.RequestEntities"/> property reflects what was parsed from the incoming request,
12-
/// where the <see cref="IAffectedResourcesDiff{TEntity}.DatabaseValues"/> reflects what is the current state in the database.
11+
/// A wrapper class that contains information about the resources that are updated by the request.
12+
/// Contains the resources from the request and the corresponding database values.
1313
///
14-
/// Any relationships that are updated can be retrieved via the methods implemented on
15-
/// <see cref="IAffectedRelationships{TDependent}"/>.
14+
/// Also contains information about updated relationships through
15+
/// implementation of IAffectedRelationshipsDictionary<typeparamref name="TResource"/>>
1616
/// </summary>
17-
public interface IAffectedResourcesDiff<TResource> : IAffectedResources<TResource> where TResource : class, IIdentifiable
17+
public interface IAffectedResourcesDiffs<TResource> : IRelationshipsDictionary<TResource>, IEnumerable<ResourceDiffPair<TResource>> where TResource : class, IIdentifiable
1818
{
1919
/// <summary>
20-
/// the current database values of the affected resources collection.
20+
/// The database values of the resources affected by the request.
2121
/// </summary>
2222
HashSet<TResource> DatabaseValues { get; }
2323

2424
/// <summary>
25-
/// Matches the resources from the request to the database values that have been loaded
26-
/// and exposes them in ResourceDiffPair wrapper
25+
/// The resources that were affected by the request.
2726
/// </summary>
28-
IEnumerable<ResourceDiffPair<TResource>> GetDiffs();
27+
HashSet<TResource> Resources { get; }
2928
}
3029

31-
public class AffectedResourceDiff<TResource> : AffectedResources<TResource>, IAffectedResourcesDiff<TResource> where TResource : class, IIdentifiable
30+
/// <inheritdoc />
31+
public class AffectedResourcesDiffs<TResource> : IAffectedResourcesDiffs<TResource> where TResource : class, IIdentifiable
3232
{
3333
private readonly HashSet<TResource> _databaseValues;
3434
private readonly bool _databaseValuesLoaded;
35+
3536
/// <inheritdoc />
3637
public HashSet<TResource> DatabaseValues { get => _databaseValues ?? ThrowNoDbValuesError(); }
38+
/// <inheritdoc />
39+
public HashSet<TResource> Resources { get; private set; }
40+
/// <inheritdoc />
41+
public RelationshipsDictionary<TResource> AffectedRelationships { get; private set; }
3742

38-
public AffectedResourceDiff(HashSet<TResource> requestEntities,
43+
public AffectedResourcesDiffs(HashSet<TResource> requestEntities,
3944
HashSet<TResource> databaseEntities,
40-
Dictionary<RelationshipAttribute, HashSet<TResource>> relationships) : base(requestEntities, relationships)
45+
Dictionary<RelationshipAttribute, HashSet<TResource>> relationships)
4146
{
47+
Resources = requestEntities;
48+
AffectedRelationships = new RelationshipsDictionary<TResource>(relationships);
4249
_databaseValues = databaseEntities;
4350
_databaseValuesLoaded |= _databaseValues != null;
4451
}
4552

4653
/// <summary>
4754
/// Used internally by the ResourceHookExecutor to make live a bit easier with generics
4855
/// </summary>
49-
internal AffectedResourceDiff(IEnumerable requestEntities,
56+
internal AffectedResourcesDiffs(IEnumerable requestEntities,
5057
IEnumerable databaseEntities,
5158
Dictionary<RelationshipAttribute, IEnumerable> relationships)
52-
: this((HashSet<TResource>)requestEntities, (HashSet<TResource>)databaseEntities, ConvertRelationshipDictionary(relationships)) { }
59+
: this((HashSet<TResource>)requestEntities, (HashSet<TResource>)databaseEntities, TypeHelper.ConvertRelationshipDictionary<TResource>(relationships)) { }
60+
61+
62+
/// <inheritdoc />
63+
public Dictionary<RelationshipAttribute, HashSet<TResource>> GetByRelationship<TPrincipalResource>() where TPrincipalResource : class, IIdentifiable
64+
{
65+
return GetByRelationship(typeof(TPrincipalResource));
66+
}
5367

5468
/// <inheritdoc />
55-
public IEnumerable<ResourceDiffPair<TResource>> GetDiffs()
69+
public Dictionary<RelationshipAttribute, HashSet<TResource>> GetByRelationship(Type principalType)
70+
{
71+
return AffectedRelationships.GetByRelationship(principalType);
72+
}
73+
74+
/// <inheritdoc />
75+
public IEnumerator<ResourceDiffPair<TResource>> GetEnumerator()
5676
{
5777
if (!_databaseValuesLoaded) ThrowNoDbValuesError();
5878

@@ -64,14 +84,18 @@ public IEnumerable<ResourceDiffPair<TResource>> GetDiffs()
6484
}
6585
}
6686

87+
/// <inheritdoc />
88+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
89+
6790
private HashSet<TResource> ThrowNoDbValuesError()
6891
{
6992
throw new MemberAccessException("Cannot access database entities if the LoadDatabaseValues option is set to false");
7093
}
7194
}
7295

7396
/// <summary>
74-
/// A wrapper that contains a resource from the request matches to its current database value
97+
/// A wrapper that contains an resource that is affected by the request,
98+
/// matched to its current database value
7599
/// </summary>
76100
public class ResourceDiffPair<TResource> where TResource : class, IIdentifiable
77101
{

src/JsonApiDotNetCore/Hooks/Execution/AffectedRelationships.cs renamed to src/JsonApiDotNetCore/Hooks/Execution/RelationshipsDictionary.cs

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,29 @@
33
using System.Collections.Generic;
44
using System.Collections.ObjectModel;
55
using System.Linq;
6+
using JsonApiDotNetCore.Internal;
67
using JsonApiDotNetCore.Models;
78

89
namespace JsonApiDotNetCore.Hooks
910
{
1011
public interface IAffectedRelationships { }
1112

1213
/// <summary>
13-
/// A helper class that provides insights in which relationships have been updated for which entities.
14+
/// An interface that is implemented to expose a relationship dictionary on another class.
1415
/// </summary>
15-
public interface IAffectedRelationships<TDependentResource> : IAffectedRelationships where TDependentResource : class, IIdentifiable
16+
public interface IRelationshipsDictionary<TDependentResource> : IRelationshipsDictionaryGetters<TDependentResource> where TDependentResource : class, IIdentifiable
1617
{
1718
/// <summary>
18-
/// Gets a dictionary of all entities grouped by affected relationship.
19+
/// Gets a dictionary of affected resources grouped by affected relationships.
1920
/// </summary>
20-
Dictionary<RelationshipAttribute, HashSet<TDependentResource>> AllByRelationships();
21+
RelationshipsDictionary<TDependentResource> AffectedRelationships { get; }
22+
}
23+
24+
/// <summary>
25+
/// A helper class that provides insights in which relationships have been updated for which entities.
26+
/// </summary>
27+
public interface IRelationshipsDictionaryGetters<TDependentResource> : IAffectedRelationships where TDependentResource : class, IIdentifiable
28+
{
2129
/// <summary>
2230
/// Gets a dictionary of all entities that have an affected relationship to type <typeparamref name="TPrincipalResource"/>
2331
/// </summary>
@@ -28,38 +36,32 @@ public interface IAffectedRelationships<TDependentResource> : IAffectedRelations
2836
Dictionary<RelationshipAttribute, HashSet<TDependentResource>> GetByRelationship(Type principalType);
2937
}
3038

31-
/// <inheritdoc />
32-
public class AffectedRelationships<TDependentResource> : IAffectedRelationships<TDependentResource> where TDependentResource : class, IIdentifiable
39+
/// <summary>
40+
/// Implementation of IAffectedRelationships{TDependentResource}
41+
///
42+
/// It is practically a ReadOnlyDictionary{RelationshipAttribute, HashSet{TDependentResource}} dictionary
43+
/// with the two helper methods defined on IAffectedRelationships{TDependentResource}.
44+
/// </summary>
45+
public class RelationshipsDictionary<TDependentResource> : ReadOnlyDictionary<RelationshipAttribute, HashSet<TDependentResource>>, IRelationshipsDictionaryGetters<TDependentResource> where TDependentResource : class, IIdentifiable
3346
{
34-
/// <summary>
35-
/// Helper method that "unboxes" the TValue from the relationship dictionary
36-
/// </summary>
37-
internal static Dictionary<RelationshipAttribute, HashSet<TDependentResource>> ConvertRelationshipDictionary(Dictionary<RelationshipAttribute, IEnumerable> relationships)
38-
{
39-
return relationships.ToDictionary(pair => pair.Key, pair => (HashSet<TDependentResource>)pair.Value);
40-
}
41-
4247
/// <summary>
4348
/// a dictionary with affected relationships as keys and values being the corresponding resources
4449
/// that were affected
4550
/// </summary>
4651
private readonly Dictionary<RelationshipAttribute, HashSet<TDependentResource>> _groups;
4752

4853
/// <inheritdoc />
49-
public AffectedRelationships(Dictionary<RelationshipAttribute, HashSet<TDependentResource>> relationships)
54+
public RelationshipsDictionary(Dictionary<RelationshipAttribute, HashSet<TDependentResource>> relationships) : base(relationships)
5055
{
5156
_groups = relationships;
5257
}
5358

5459
/// <summary>
5560
/// Used internally by the ResourceHookExecutor to make live a bit easier with generics
5661
/// </summary>
57-
internal AffectedRelationships(Dictionary<RelationshipAttribute, IEnumerable> relationships) : this(ConvertRelationshipDictionary(relationships)) { }
62+
internal RelationshipsDictionary(Dictionary<RelationshipAttribute, IEnumerable> relationships)
63+
: this(TypeHelper.ConvertRelationshipDictionary<TDependentResource>(relationships)) { }
5864

59-
public Dictionary<RelationshipAttribute, HashSet<TDependentResource>> AllByRelationships()
60-
{
61-
return _groups;
62-
}
6365

6466
/// <inheritdoc />
6567
public Dictionary<RelationshipAttribute, HashSet<TDependentResource>> GetByRelationship<TPrincipalResource>() where TPrincipalResource : class, IIdentifiable
@@ -70,7 +72,7 @@ public Dictionary<RelationshipAttribute, HashSet<TDependentResource>> GetByRelat
7072
/// <inheritdoc />
7173
public Dictionary<RelationshipAttribute, HashSet<TDependentResource>> GetByRelationship(Type principalType)
7274
{
73-
return _groups?.Where(p => p.Key.PrincipalType == principalType).ToDictionary(p => p.Key, p => p.Value);
75+
return this.Where(p => p.Key.PrincipalType == principalType).ToDictionary(p => p.Key, p => p.Value);
7476
}
7577
}
7678
}

0 commit comments

Comments
 (0)