Skip to content

Commit 9010f16

Browse files
authored
Merge pull request #1645 from json-api-dotnet/merge-master-into-openapi
Merge master into openapi
2 parents e5a7084 + 575f579 commit 9010f16

29 files changed

+334
-129
lines changed

Directory.Build.props

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)CodingGuidelines.ruleset</CodeAnalysisRuleSet>
1111
<RunSettingsFilePath>$(MSBuildThisFileDirectory)tests.runsettings</RunSettingsFilePath>
1212
<JsonApiDotNetCoreVersionPrefix>5.6.1</JsonApiDotNetCoreVersionPrefix>
13+
<NuGetAuditMode>direct</NuGetAuditMode>
14+
<NoWarn>$(NoWarn);NETSDK1215</NoWarn>
1315
</PropertyGroup>
1416

1517
<PropertyGroup>

JsonApiDotNetCore.sln.DotSettings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ $left$ = $right$;</s:String>
672672
<s:String x:Key="/Default/PatternsAndTemplates/StructuralSearch/Pattern/=D29C3A091CD9E74BBFDF1B8974F5A977/SearchPattern/@EntryValue">if ($argument$ is null) throw new ArgumentNullException(nameof($argument$));</s:String>
673673
<s:String x:Key="/Default/PatternsAndTemplates/StructuralSearch/Pattern/=D29C3A091CD9E74BBFDF1B8974F5A977/Severity/@EntryValue">WARNING</s:String>
674674
<s:Boolean x:Key="/Default/UserDictionary/Words/=Accurize/@EntryIndexedValue">True</s:Boolean>
675+
<s:Boolean x:Key="/Default/UserDictionary/Words/=accurized/@EntryIndexedValue">True</s:Boolean>
675676
<s:Boolean x:Key="/Default/UserDictionary/Words/=appsettings/@EntryIndexedValue">True</s:Boolean>
676677
<s:Boolean x:Key="/Default/UserDictionary/Words/=Assignee/@EntryIndexedValue">True</s:Boolean>
677678
<s:Boolean x:Key="/Default/UserDictionary/Words/=Contoso/@EntryIndexedValue">True</s:Boolean>

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,16 @@ See also our [versioning policy](./VERSIONING_POLICY.md).
8585
| | | 7 | 7 |
8686
| 5.5+ | Stable | 6 | 6, 7 |
8787
| | | 7 | 7 |
88-
| | | 8 | 8 |
88+
| | | 8 | 8, 9 |
89+
| | | 9 | 9 |
8990
| master | Preview | 6 | 6, 7 |
9091
| | | 7 | 7 |
91-
| | | 8 | 8 |
92+
| | | 8 | 8, 9 |
93+
| | | 9 | 9 |
9294
| openapi | Experimental | 6 | 6, 7 |
9395
| | | 7 | 7 |
94-
| | | 8 | 8 |
96+
| | | 8 | 8, 9 |
97+
| | | 9 | 9 |
9598

9699
## Contributing
97100

src/Examples/DapperExample/Repositories/DapperRepository.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ public sealed partial class DapperRepository<TResource, TId> : IResourceReposito
103103
private readonly SqlCaptureStore _captureStore;
104104
private readonly ILoggerFactory _loggerFactory;
105105
private readonly ILogger<DapperRepository<TResource, TId>> _logger;
106-
private readonly CollectionConverter _collectionConverter = new();
107106
private readonly ParameterFormatter _parameterFormatter = new();
108107
private readonly DapperFacade _dapperFacade;
109108

@@ -270,12 +269,12 @@ private async Task ApplyTargetedFieldsAsync(TResource resourceFromRequest, TReso
270269

271270
if (relationship is HasManyAttribute hasManyRelationship)
272271
{
273-
HashSet<IIdentifiable> rightResourceIds = _collectionConverter.ExtractResources(rightValue).ToHashSet(IdentifiableComparer.Instance);
272+
HashSet<IIdentifiable> rightResourceIds = CollectionConverter.Instance.ExtractResources(rightValue).ToHashSet(IdentifiableComparer.Instance);
274273

275274
await _resourceDefinitionAccessor.OnSetToManyRelationshipAsync(leftResource, hasManyRelationship, rightResourceIds, writeOperation,
276275
cancellationToken);
277276

278-
return _collectionConverter.CopyToTypedCollection(rightResourceIds, relationship.Property.PropertyType);
277+
return CollectionConverter.Instance.CopyToTypedCollection(rightResourceIds, relationship.Property.PropertyType);
279278
}
280279

281280
return rightValue;
@@ -464,7 +463,9 @@ public async Task AddToToManyRelationshipAsync(TResource? leftResource, [Disallo
464463
leftPlaceholderResource.Id = leftId;
465464

466465
await _resourceDefinitionAccessor.OnAddToRelationshipAsync(leftPlaceholderResource, relationship, rightResourceIds, cancellationToken);
467-
relationship.SetValue(leftPlaceholderResource, _collectionConverter.CopyToTypedCollection(rightResourceIds, relationship.Property.PropertyType));
466+
467+
relationship.SetValue(leftPlaceholderResource,
468+
CollectionConverter.Instance.CopyToTypedCollection(rightResourceIds, relationship.Property.PropertyType));
468469

469470
await _resourceDefinitionAccessor.OnWritingAsync(leftPlaceholderResource, WriteOperationKind.AddToRelationship, cancellationToken);
470471

@@ -500,7 +501,7 @@ public async Task RemoveFromToManyRelationshipAsync(TResource leftResource, ISet
500501
var relationship = (HasManyAttribute)_targetedFields.Relationships.Single();
501502

502503
await _resourceDefinitionAccessor.OnRemoveFromRelationshipAsync(leftResource, relationship, rightResourceIds, cancellationToken);
503-
relationship.SetValue(leftResource, _collectionConverter.CopyToTypedCollection(rightResourceIds, relationship.Property.PropertyType));
504+
relationship.SetValue(leftResource, CollectionConverter.Instance.CopyToTypedCollection(rightResourceIds, relationship.Property.PropertyType));
504505

505506
await _resourceDefinitionAccessor.OnWritingAsync(leftResource, WriteOperationKind.RemoveFromRelationship, cancellationToken);
506507

src/Examples/DapperExample/Repositories/ResourceChangeDetector.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ namespace DapperExample.Repositories;
1212
/// </summary>
1313
internal sealed class ResourceChangeDetector
1414
{
15-
private readonly CollectionConverter _collectionConverter = new();
1615
private readonly IDataModelService _dataModelService;
1716

1817
private Dictionary<string, object?> _currentColumnValues = [];
@@ -69,7 +68,7 @@ private Dictionary<RelationshipAttribute, HashSet<IIdentifiable>> CaptureRightRe
6968
foreach (RelationshipAttribute relationship in ResourceType.Relationships)
7069
{
7170
object? rightValue = relationship.GetValue(resource);
72-
HashSet<IIdentifiable> rightResources = _collectionConverter.ExtractResources(rightValue).ToHashSet(IdentifiableComparer.Instance);
71+
HashSet<IIdentifiable> rightResources = CollectionConverter.Instance.ExtractResources(rightValue).ToHashSet(IdentifiableComparer.Instance);
7372

7473
relationshipValues[relationship] = rightResources;
7574
}

src/Examples/OpenApiKiotaClientExample/PeopleMessageFormatter.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,28 +34,27 @@ private static string WritePeople(PersonCollectionResponseDocument? peopleRespon
3434
return builder.ToString();
3535
}
3636

37-
private static void WritePerson(PersonDataInResponse person, ICollection<DataInResponse> includes, StringBuilder builder)
37+
private static void WritePerson(PersonDataInResponse person, List<DataInResponse> includes, StringBuilder builder)
3838
{
39-
ICollection<TodoItemIdentifierInResponse> assignedTodoItems = person.Relationships?.AssignedTodoItems?.Data ?? [];
39+
List<TodoItemIdentifierInResponse> assignedTodoItems = person.Relationships?.AssignedTodoItems?.Data ?? [];
4040

4141
builder.AppendLine($" Person {person.Id}: {person.Attributes?.DisplayName} with {assignedTodoItems.Count} assigned todo-items:");
4242
WriteRelatedTodoItems(assignedTodoItems, includes, builder);
4343
}
4444

45-
private static void WriteRelatedTodoItems(IEnumerable<TodoItemIdentifierInResponse> todoItemIdentifiers, ICollection<DataInResponse> includes,
46-
StringBuilder builder)
45+
private static void WriteRelatedTodoItems(List<TodoItemIdentifierInResponse> todoItemIdentifiers, List<DataInResponse> includes, StringBuilder builder)
4746
{
4847
foreach (TodoItemIdentifierInResponse todoItemIdentifier in todoItemIdentifiers)
4948
{
5049
TodoItemDataInResponse includedTodoItem = includes.OfType<TodoItemDataInResponse>().Single(include => include.Id == todoItemIdentifier.Id);
51-
ICollection<TagIdentifierInResponse> tags = includedTodoItem.Relationships?.Tags?.Data ?? [];
50+
List<TagIdentifierInResponse> tags = includedTodoItem.Relationships?.Tags?.Data ?? [];
5251

5352
builder.AppendLine($" TodoItem {includedTodoItem.Id}: {includedTodoItem.Attributes?.Description} with {tags.Count} tags:");
5453
WriteRelatedTags(tags, includes, builder);
5554
}
5655
}
5756

58-
private static void WriteRelatedTags(IEnumerable<TagIdentifierInResponse> tagIdentifiers, ICollection<DataInResponse> includes, StringBuilder builder)
57+
private static void WriteRelatedTags(List<TagIdentifierInResponse> tagIdentifiers, List<DataInResponse> includes, StringBuilder builder)
5958
{
6059
foreach (TagIdentifierInResponse tagIdentifier in tagIdentifiers)
6160
{

src/JsonApiDotNetCore.Annotations/CollectionConverter.cs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,24 @@ internal sealed class CollectionConverter
1515
typeof(IEnumerable<>)
1616
];
1717

18+
public static CollectionConverter Instance { get; } = new();
19+
20+
private CollectionConverter()
21+
{
22+
}
23+
1824
/// <summary>
1925
/// Creates a collection instance based on the specified collection type and copies the specified elements into it.
2026
/// </summary>
2127
/// <param name="source">
2228
/// Source to copy from.
2329
/// </param>
2430
/// <param name="collectionType">
25-
/// Target collection type, for example: typeof(List{Article}) or typeof(ISet{Person}).
31+
/// Target collection type, for example: <code><![CDATA[
32+
/// typeof(List<Article>)
33+
/// ]]></code> or <code><![CDATA[
34+
/// typeof(ISet<Person>)
35+
/// ]]></code>.
2636
/// </param>
2737
public IEnumerable CopyToTypedCollection(IEnumerable source, Type collectionType)
2838
{
@@ -41,7 +51,12 @@ public IEnumerable CopyToTypedCollection(IEnumerable source, Type collectionType
4151
}
4252

4353
/// <summary>
44-
/// Returns a compatible collection type that can be instantiated, for example IList{Article} -> List{Article} or ISet{Article} -> HashSet{Article}
54+
/// Returns a compatible collection type that can be instantiated, for example: <code><![CDATA[
55+
/// IList<Article> -> List<Article>
56+
/// ]]></code> or
57+
/// <code><![CDATA[
58+
/// ISet<Article> -> HashSet<Article>
59+
/// ]]></code>.
4560
/// </summary>
4661
private Type ToConcreteCollectionType(Type collectionType)
4762
{
@@ -80,7 +95,12 @@ public IReadOnlyCollection<IIdentifiable> ExtractResources(object? value)
8095
}
8196

8297
/// <summary>
83-
/// Returns the element type if the specified type is a generic collection, for example: IList{string} -> string or IList -> null.
98+
/// Returns the element type if the specified type is a generic collection, for example: <code><![CDATA[
99+
/// IList<string> -> string
100+
/// ]]></code> or
101+
/// <code><![CDATA[
102+
/// IList -> null
103+
/// ]]></code>.
84104
/// </summary>
85105
public Type? FindCollectionElementType(Type? type)
86106
{
@@ -96,8 +116,12 @@ public IReadOnlyCollection<IIdentifiable> ExtractResources(object? value)
96116
}
97117

98118
/// <summary>
99-
/// Indicates whether a <see cref="HashSet{T}" /> instance can be assigned to the specified type, for example IList{Article} -> false or ISet{Article} ->
100-
/// true.
119+
/// Indicates whether a <see cref="HashSet{T}" /> instance can be assigned to the specified type, for example:
120+
/// <code><![CDATA[
121+
/// IList<Article> -> false
122+
/// ]]></code> or <code><![CDATA[
123+
/// ISet<Article> -> true
124+
/// ]]></code>.
101125
/// </summary>
102126
public bool TypeCanContainHashSet(Type collectionType)
103127
{

src/JsonApiDotNetCore.Annotations/Resources/Annotations/HasManyAttribute.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ private bool EvaluateIsManyToMany()
5959
{
6060
if (InverseNavigationProperty != null)
6161
{
62-
Type? elementType = CollectionConverter.FindCollectionElementType(InverseNavigationProperty.PropertyType);
62+
Type? elementType = CollectionConverter.Instance.FindCollectionElementType(InverseNavigationProperty.PropertyType);
6363
return elementType != null;
6464
}
6565

@@ -103,14 +103,14 @@ public void AddValue(object resource, IIdentifiable resourceToAdd)
103103
ArgumentGuard.NotNull(resourceToAdd);
104104

105105
object? rightValue = GetValue(resource);
106-
List<IIdentifiable> rightResources = CollectionConverter.ExtractResources(rightValue).ToList();
106+
List<IIdentifiable> rightResources = CollectionConverter.Instance.ExtractResources(rightValue).ToList();
107107

108108
if (!rightResources.Exists(nextResource => nextResource == resourceToAdd))
109109
{
110110
rightResources.Add(resourceToAdd);
111111

112112
Type collectionType = rightValue?.GetType() ?? Property.PropertyType;
113-
IEnumerable typedCollection = CollectionConverter.CopyToTypedCollection(rightResources, collectionType);
113+
IEnumerable typedCollection = CollectionConverter.Instance.CopyToTypedCollection(rightResources, collectionType);
114114
base.SetValue(resource, typedCollection);
115115
}
116116
}

src/JsonApiDotNetCore.Annotations/Resources/Annotations/HasOneAttribute.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ private bool EvaluateIsOneToOne()
5757
{
5858
if (InverseNavigationProperty != null)
5959
{
60-
Type? elementType = CollectionConverter.FindCollectionElementType(InverseNavigationProperty.PropertyType);
60+
Type? elementType = CollectionConverter.Instance.FindCollectionElementType(InverseNavigationProperty.PropertyType);
6161
return elementType == null;
6262
}
6363

src/JsonApiDotNetCore.Annotations/Resources/Annotations/RelationshipAttribute.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ namespace JsonApiDotNetCore.Resources.Annotations;
1212
[PublicAPI]
1313
public abstract class RelationshipAttribute : ResourceFieldAttribute
1414
{
15-
private protected static readonly CollectionConverter CollectionConverter = new();
16-
1715
// This field is definitely assigned after building the resource graph, which is why its public equivalent is declared as non-nullable.
1816
private ResourceType? _rightType;
1917

0 commit comments

Comments
 (0)