1
1
using System ;
2
2
using System . Collections . Generic ;
3
+ using System . Collections . Immutable ;
3
4
using System . Linq ;
4
5
using JetBrains . Annotations ;
5
6
using JsonApiDotNetCore . Configuration ;
@@ -17,20 +18,21 @@ namespace JsonApiDotNetCore.Queries.Internal
17
18
public sealed class SparseFieldSetCache
18
19
{
19
20
private readonly IResourceDefinitionAccessor _resourceDefinitionAccessor ;
20
- private readonly Lazy < IDictionary < ResourceContext , HashSet < ResourceFieldAttribute > > > _lazySourceTable ;
21
- private readonly IDictionary < ResourceContext , HashSet < ResourceFieldAttribute > > _visitedTable ;
21
+ private readonly Lazy < IDictionary < ResourceContext , IImmutableSet < ResourceFieldAttribute > > > _lazySourceTable ;
22
+ private readonly IDictionary < ResourceContext , IImmutableSet < ResourceFieldAttribute > > _visitedTable ;
22
23
23
24
public SparseFieldSetCache ( IEnumerable < IQueryConstraintProvider > constraintProviders , IResourceDefinitionAccessor resourceDefinitionAccessor )
24
25
{
25
26
ArgumentGuard . NotNull ( constraintProviders , nameof ( constraintProviders ) ) ;
26
27
ArgumentGuard . NotNull ( resourceDefinitionAccessor , nameof ( resourceDefinitionAccessor ) ) ;
27
28
28
29
_resourceDefinitionAccessor = resourceDefinitionAccessor ;
29
- _lazySourceTable = new Lazy < IDictionary < ResourceContext , HashSet < ResourceFieldAttribute > > > ( ( ) => BuildSourceTable ( constraintProviders ) ) ;
30
- _visitedTable = new Dictionary < ResourceContext , HashSet < ResourceFieldAttribute > > ( ) ;
30
+ _lazySourceTable = new Lazy < IDictionary < ResourceContext , IImmutableSet < ResourceFieldAttribute > > > ( ( ) => BuildSourceTable ( constraintProviders ) ) ;
31
+ _visitedTable = new Dictionary < ResourceContext , IImmutableSet < ResourceFieldAttribute > > ( ) ;
31
32
}
32
33
33
- private static IDictionary < ResourceContext , HashSet < ResourceFieldAttribute > > BuildSourceTable ( IEnumerable < IQueryConstraintProvider > constraintProviders )
34
+ private static IDictionary < ResourceContext , IImmutableSet < ResourceFieldAttribute > > BuildSourceTable (
35
+ IEnumerable < IQueryConstraintProvider > constraintProviders )
34
36
{
35
37
// @formatter:wrap_chained_method_calls chop_always
36
38
// @formatter:keep_existing_linebreaks true
@@ -47,30 +49,31 @@ private static IDictionary<ResourceContext, HashSet<ResourceFieldAttribute>> Bui
47
49
// @formatter:keep_existing_linebreaks restore
48
50
// @formatter:wrap_chained_method_calls restore
49
51
50
- var mergedTable = new Dictionary < ResourceContext , HashSet < ResourceFieldAttribute > > ( ) ;
52
+ var mergedTable = new Dictionary < ResourceContext , ImmutableHashSet < ResourceFieldAttribute > . Builder > ( ) ;
51
53
52
54
foreach ( ( ResourceContext resourceContext , SparseFieldSetExpression sparseFieldSet ) in sparseFieldTables )
53
55
{
54
56
if ( ! mergedTable . ContainsKey ( resourceContext ) )
55
57
{
56
- mergedTable [ resourceContext ] = new HashSet < ResourceFieldAttribute > ( ) ;
58
+ mergedTable [ resourceContext ] = ImmutableHashSet . CreateBuilder < ResourceFieldAttribute > ( ) ;
57
59
}
58
60
59
61
AddSparseFieldsToSet ( sparseFieldSet . Fields , mergedTable [ resourceContext ] ) ;
60
62
}
61
63
62
- return mergedTable ;
64
+ return mergedTable . ToDictionary ( pair => pair . Key , pair => ( IImmutableSet < ResourceFieldAttribute > ) pair . Value . ToImmutable ( ) ) ;
63
65
}
64
66
65
- private static void AddSparseFieldsToSet ( IReadOnlyCollection < ResourceFieldAttribute > sparseFieldsToAdd , HashSet < ResourceFieldAttribute > sparseFieldSet )
67
+ private static void AddSparseFieldsToSet ( IImmutableSet < ResourceFieldAttribute > sparseFieldsToAdd ,
68
+ ImmutableHashSet < ResourceFieldAttribute > . Builder sparseFieldSetBuilder )
66
69
{
67
70
foreach ( ResourceFieldAttribute field in sparseFieldsToAdd )
68
71
{
69
- sparseFieldSet . Add ( field ) ;
72
+ sparseFieldSetBuilder . Add ( field ) ;
70
73
}
71
74
}
72
75
73
- public IReadOnlyCollection < ResourceFieldAttribute > GetSparseFieldSetForQuery ( ResourceContext resourceContext )
76
+ public IImmutableSet < ResourceFieldAttribute > GetSparseFieldSetForQuery ( ResourceContext resourceContext )
74
77
{
75
78
ArgumentGuard . NotNull ( resourceContext , nameof ( resourceContext ) ) ;
76
79
@@ -82,84 +85,73 @@ public IReadOnlyCollection<ResourceFieldAttribute> GetSparseFieldSetForQuery(Res
82
85
83
86
SparseFieldSetExpression outputExpression = _resourceDefinitionAccessor . OnApplySparseFieldSet ( resourceContext . ResourceType , inputExpression ) ;
84
87
85
- HashSet < ResourceFieldAttribute > outputFields = outputExpression == null
86
- ? new HashSet < ResourceFieldAttribute > ( )
87
- : outputExpression . Fields . ToHashSet ( ) ;
88
+ IImmutableSet < ResourceFieldAttribute > outputFields = outputExpression == null
89
+ ? ImmutableHashSet < ResourceFieldAttribute > . Empty
90
+ : outputExpression . Fields ;
88
91
89
92
_visitedTable [ resourceContext ] = outputFields ;
90
93
}
91
94
92
95
return _visitedTable [ resourceContext ] ;
93
96
}
94
97
95
- public IReadOnlyCollection < AttrAttribute > GetIdAttributeSetForRelationshipQuery ( ResourceContext resourceContext )
98
+ public IImmutableSet < AttrAttribute > GetIdAttributeSetForRelationshipQuery ( ResourceContext resourceContext )
96
99
{
97
100
ArgumentGuard . NotNull ( resourceContext , nameof ( resourceContext ) ) ;
98
101
99
102
AttrAttribute idAttribute = resourceContext . Attributes . Single ( attr => attr . Property . Name == nameof ( Identifiable . Id ) ) ;
100
- var inputExpression = new SparseFieldSetExpression ( idAttribute . AsArray ( ) ) ;
103
+ var inputExpression = new SparseFieldSetExpression ( ImmutableHashSet . Create < ResourceFieldAttribute > ( idAttribute ) ) ;
101
104
102
105
// Intentionally not cached, as we are fetching ID only (ignoring any sparse fieldset that came from query string).
103
106
SparseFieldSetExpression outputExpression = _resourceDefinitionAccessor . OnApplySparseFieldSet ( resourceContext . ResourceType , inputExpression ) ;
104
107
105
- HashSet < AttrAttribute > outputAttributes = outputExpression == null
106
- ? new HashSet < AttrAttribute > ( )
107
- : outputExpression . Fields . OfType < AttrAttribute > ( ) . ToHashSet ( ) ;
108
+ ImmutableHashSet < AttrAttribute > outputAttributes = outputExpression == null
109
+ ? ImmutableHashSet < AttrAttribute > . Empty
110
+ : outputExpression . Fields . OfType < AttrAttribute > ( ) . ToImmutableHashSet ( ) ;
108
111
109
- outputAttributes . Add ( idAttribute ) ;
112
+ outputAttributes = outputAttributes . Add ( idAttribute ) ;
110
113
return outputAttributes ;
111
114
}
112
115
113
- public IReadOnlyCollection < ResourceFieldAttribute > GetSparseFieldSetForSerializer ( ResourceContext resourceContext )
116
+ public IImmutableSet < ResourceFieldAttribute > GetSparseFieldSetForSerializer ( ResourceContext resourceContext )
114
117
{
115
118
ArgumentGuard . NotNull ( resourceContext , nameof ( resourceContext ) ) ;
116
119
117
120
if ( ! _visitedTable . ContainsKey ( resourceContext ) )
118
121
{
119
- HashSet < ResourceFieldAttribute > inputFields = _lazySourceTable . Value . ContainsKey ( resourceContext )
122
+ IImmutableSet < ResourceFieldAttribute > inputFields = _lazySourceTable . Value . ContainsKey ( resourceContext )
120
123
? _lazySourceTable . Value [ resourceContext ]
121
124
: GetResourceFields ( resourceContext ) ;
122
125
123
126
var inputExpression = new SparseFieldSetExpression ( inputFields ) ;
124
127
SparseFieldSetExpression outputExpression = _resourceDefinitionAccessor . OnApplySparseFieldSet ( resourceContext . ResourceType , inputExpression ) ;
125
128
126
- HashSet < ResourceFieldAttribute > outputFields ;
127
-
128
- if ( outputExpression == null )
129
- {
130
- outputFields = GetResourceFields ( resourceContext ) ;
131
- }
132
- else
133
- {
134
- outputFields = new HashSet < ResourceFieldAttribute > ( inputFields ) ;
135
- outputFields . IntersectWith ( outputExpression . Fields ) ;
136
- }
129
+ IImmutableSet < ResourceFieldAttribute > outputFields =
130
+ outputExpression == null ? GetResourceFields ( resourceContext ) : inputFields . Intersect ( outputExpression . Fields ) ;
137
131
138
132
_visitedTable [ resourceContext ] = outputFields ;
139
133
}
140
134
141
135
return _visitedTable [ resourceContext ] ;
142
136
}
143
137
144
- #pragma warning disable AV1130 // Return type in method signature should be a collection interface instead of a concrete type
145
- private HashSet < ResourceFieldAttribute > GetResourceFields ( ResourceContext resourceContext )
146
- #pragma warning restore AV1130 // Return type in method signature should be a collection interface instead of a concrete type
138
+ private IImmutableSet < ResourceFieldAttribute > GetResourceFields ( ResourceContext resourceContext )
147
139
{
148
140
ArgumentGuard . NotNull ( resourceContext , nameof ( resourceContext ) ) ;
149
141
150
- var fieldSet = new HashSet < ResourceFieldAttribute > ( ) ;
142
+ ImmutableHashSet < ResourceFieldAttribute > . Builder fieldSetBuilder = ImmutableHashSet . CreateBuilder < ResourceFieldAttribute > ( ) ;
151
143
152
144
foreach ( AttrAttribute attribute in resourceContext . Attributes . Where ( attr => attr . Capabilities . HasFlag ( AttrCapabilities . AllowView ) ) )
153
145
{
154
- fieldSet . Add ( attribute ) ;
146
+ fieldSetBuilder . Add ( attribute ) ;
155
147
}
156
148
157
149
foreach ( RelationshipAttribute relationship in resourceContext . Relationships )
158
150
{
159
- fieldSet . Add ( relationship ) ;
151
+ fieldSetBuilder . Add ( relationship ) ;
160
152
}
161
153
162
- return fieldSet ;
154
+ return fieldSetBuilder . ToImmutable ( ) ;
163
155
}
164
156
165
157
public void Reset ( )
0 commit comments