Skip to content

Commit 0ca0c12

Browse files
committed
Fixed: full linkage does not allow primary resources to occur in included
1 parent d71ea37 commit 0ca0c12

File tree

7 files changed

+54
-43
lines changed

7 files changed

+54
-43
lines changed

Diff for: src/JsonApiDotNetCore/Serialization/Response/ResourceObjectTreeNode.cs

+11-1
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,17 @@ public IList<ResourceObject> GetResponseIncluded()
181181
VisitRelationshipChildrenInSubtree(child, visited);
182182
}
183183

184-
return visited.Select(node => node.ResourceObject).ToArray();
184+
List<ResourceObject> includes = visited.Select(node => node.ResourceObject).ToList();
185+
186+
foreach (ResourceObject primaryResourceObjects in GetDirectChildren().Select(node => node.ResourceObject))
187+
{
188+
if (includes.Contains(primaryResourceObjects))
189+
{
190+
includes.Remove(primaryResourceObjects);
191+
}
192+
}
193+
194+
return includes;
185195
}
186196

187197
private IList<ResourceObjectTreeNode> GetDirectChildren()

Diff for: test/JsonApiDotNetCoreTests/IntegrationTests/QueryStrings/Includes/IncludeTests.cs

+9-13
Original file line numberDiff line numberDiff line change
@@ -398,29 +398,25 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
398398
responseDocument.Data.SingleValue.Id.Should().Be(comment.StringId);
399399
responseDocument.Data.SingleValue.Attributes.ShouldContainKey("text").With(value => value.Should().Be(comment.Text));
400400

401-
responseDocument.Included.ShouldHaveCount(5);
401+
responseDocument.Included.ShouldHaveCount(4);
402402

403403
responseDocument.Included[0].Type.Should().Be("blogPosts");
404404
responseDocument.Included[0].Id.Should().Be(comment.Parent.StringId);
405405
responseDocument.Included[0].Attributes.ShouldContainKey("caption").With(value => value.Should().Be(comment.Parent.Caption));
406406

407407
responseDocument.Included[1].Type.Should().Be("comments");
408-
responseDocument.Included[1].Id.Should().Be(comment.StringId);
409-
responseDocument.Included[1].Attributes.ShouldContainKey("text").With(value => value.Should().Be(comment.Text));
410-
411-
responseDocument.Included[2].Type.Should().Be("comments");
412-
responseDocument.Included[2].Id.Should().Be(comment.Parent.Comments.ElementAt(0).StringId);
413-
responseDocument.Included[2].Attributes.ShouldContainKey("text").With(value => value.Should().Be(comment.Parent.Comments.ElementAt(0).Text));
408+
responseDocument.Included[1].Id.Should().Be(comment.Parent.Comments.ElementAt(0).StringId);
409+
responseDocument.Included[1].Attributes.ShouldContainKey("text").With(value => value.Should().Be(comment.Parent.Comments.ElementAt(0).Text));
414410

415411
string userName = comment.Parent.Comments.ElementAt(0).Author!.UserName;
416412

417-
responseDocument.Included[3].Type.Should().Be("webAccounts");
418-
responseDocument.Included[3].Id.Should().Be(comment.Parent.Comments.ElementAt(0).Author!.StringId);
419-
responseDocument.Included[3].Attributes.ShouldContainKey("userName").With(value => value.Should().Be(userName));
413+
responseDocument.Included[2].Type.Should().Be("webAccounts");
414+
responseDocument.Included[2].Id.Should().Be(comment.Parent.Comments.ElementAt(0).Author!.StringId);
415+
responseDocument.Included[2].Attributes.ShouldContainKey("userName").With(value => value.Should().Be(userName));
420416

421-
responseDocument.Included[4].Type.Should().Be("comments");
422-
responseDocument.Included[4].Id.Should().Be(comment.Parent.Comments.ElementAt(1).StringId);
423-
responseDocument.Included[4].Attributes.ShouldContainKey("text").With(value => value.Should().Be(comment.Parent.Comments.ElementAt(1).Text));
417+
responseDocument.Included[3].Type.Should().Be("comments");
418+
responseDocument.Included[3].Id.Should().Be(comment.Parent.Comments.ElementAt(1).StringId);
419+
responseDocument.Included[3].Attributes.ShouldContainKey("text").With(value => value.Should().Be(comment.Parent.Comments.ElementAt(1).Text));
424420
}
425421

426422
[Fact]

Diff for: test/JsonApiDotNetCoreTests/IntegrationTests/ResourceDefinitions/Reading/IClientSettingsProvider.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ public interface IClientSettingsProvider
44
{
55
bool IsIncludePlanetMoonsBlocked { get; }
66
bool ArePlanetsWithPrivateNameHidden { get; }
7-
bool IsMoonOrbitingPlanetAutoIncluded { get; }
7+
bool IsStarGivingLightToMoonAutoIncluded { get; }
88
}

Diff for: test/JsonApiDotNetCoreTests/IntegrationTests/ResourceDefinitions/Reading/Moon.cs

+3
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ public sealed class Moon : Identifiable<int>
1616

1717
[HasOne]
1818
public Planet OrbitsAround { get; set; } = null!;
19+
20+
[HasOne]
21+
public Star? IsGivenLightBy { get; set; }
1922
}

Diff for: test/JsonApiDotNetCoreTests/IntegrationTests/ResourceDefinitions/Reading/MoonDefinition.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ public override IImmutableSet<IncludeElementExpression> OnApplyIncludes(IImmutab
2828
{
2929
base.OnApplyIncludes(existingIncludes);
3030

31-
if (!_clientSettingsProvider.IsMoonOrbitingPlanetAutoIncluded ||
32-
existingIncludes.Any(include => include.Relationship.Property.Name == nameof(Moon.OrbitsAround)))
31+
if (!_clientSettingsProvider.IsStarGivingLightToMoonAutoIncluded ||
32+
existingIncludes.Any(include => include.Relationship.Property.Name == nameof(Moon.IsGivenLightBy)))
3333
{
3434
return existingIncludes;
3535
}
3636

37-
RelationshipAttribute orbitsAroundRelationship = ResourceType.GetRelationshipByPropertyName(nameof(Moon.OrbitsAround));
37+
RelationshipAttribute isGivenLightByRelationship = ResourceType.GetRelationshipByPropertyName(nameof(Moon.IsGivenLightBy));
3838

39-
return existingIncludes.Add(new IncludeElementExpression(orbitsAroundRelationship));
39+
return existingIncludes.Add(new IncludeElementExpression(isGivenLightByRelationship));
4040
}
4141

4242
public override QueryStringParameterHandlers<Moon> OnRegisterQueryableHandlersForQueryStringParameters()

Diff for: test/JsonApiDotNetCoreTests/IntegrationTests/ResourceDefinitions/Reading/ResourceDefinitionReadTests.cs

+22-20
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,11 @@ public async Task Include_from_resource_definition_is_added()
9393
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
9494

9595
var settingsProvider = (TestClientSettingsProvider)_testContext.Factory.Services.GetRequiredService<IClientSettingsProvider>();
96-
settingsProvider.AutoIncludeOrbitingPlanetForMoons();
96+
settingsProvider.AutoIncludeStarGivingLightToMoon();
9797

9898
Moon moon = _fakers.Moon.Generate();
9999
moon.OrbitsAround = _fakers.Planet.Generate();
100+
moon.IsGivenLightBy = _fakers.Star.Generate();
100101

101102
await _testContext.RunOnDatabaseAsync(async dbContext =>
102103
{
@@ -114,18 +115,18 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
114115

115116
responseDocument.Data.SingleValue.ShouldNotBeNull();
116117

117-
responseDocument.Data.SingleValue.Relationships.ShouldContainKey("orbitsAround").With(value =>
118+
responseDocument.Data.SingleValue.Relationships.ShouldContainKey("isGivenLightBy").With(value =>
118119
{
119120
value.ShouldNotBeNull();
120121
value.Data.SingleValue.ShouldNotBeNull();
121-
value.Data.SingleValue.Type.Should().Be("planets");
122-
value.Data.SingleValue.Id.Should().Be(moon.OrbitsAround.StringId);
122+
value.Data.SingleValue.Type.Should().Be("stars");
123+
value.Data.SingleValue.Id.Should().Be(moon.IsGivenLightBy.StringId);
123124
});
124125

125126
responseDocument.Included.ShouldHaveCount(1);
126-
responseDocument.Included[0].Type.Should().Be("planets");
127-
responseDocument.Included[0].Id.Should().Be(moon.OrbitsAround.StringId);
128-
responseDocument.Included[0].Attributes.ShouldContainKey("publicName").With(value => value.Should().Be(moon.OrbitsAround.PublicName));
127+
responseDocument.Included[0].Type.Should().Be("stars");
128+
responseDocument.Included[0].Id.Should().Be(moon.IsGivenLightBy.StringId);
129+
responseDocument.Included[0].Attributes.ShouldContainKey("name").With(value => value.Should().Be(moon.IsGivenLightBy.Name));
129130

130131
hitCounter.HitExtensibilityPoints.Should().BeEquivalentTo(new[]
131132
{
@@ -134,12 +135,12 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
134135
(typeof(Moon), ResourceDefinitionExtensibilityPoints.OnApplySort),
135136
(typeof(Moon), ResourceDefinitionExtensibilityPoints.OnApplySparseFieldSet),
136137
(typeof(Moon), ResourceDefinitionExtensibilityPoints.OnApplyIncludes),
137-
(typeof(Planet), ResourceDefinitionExtensibilityPoints.OnApplySparseFieldSet),
138-
(typeof(Planet), ResourceDefinitionExtensibilityPoints.OnApplyIncludes),
138+
(typeof(Star), ResourceDefinitionExtensibilityPoints.OnApplySparseFieldSet),
139+
(typeof(Star), ResourceDefinitionExtensibilityPoints.OnApplyIncludes),
139140
(typeof(Moon), ResourceDefinitionExtensibilityPoints.OnApplySparseFieldSet),
140141
(typeof(Moon), ResourceDefinitionExtensibilityPoints.GetMeta),
141-
(typeof(Planet), ResourceDefinitionExtensibilityPoints.OnApplySparseFieldSet),
142-
(typeof(Planet), ResourceDefinitionExtensibilityPoints.GetMeta)
142+
(typeof(Star), ResourceDefinitionExtensibilityPoints.OnApplySparseFieldSet),
143+
(typeof(Star), ResourceDefinitionExtensibilityPoints.GetMeta)
143144
}, options => options.WithStrictOrdering());
144145
}
145146

@@ -150,11 +151,11 @@ public async Task Include_from_included_resource_definition_is_added()
150151
var hitCounter = _testContext.Factory.Services.GetRequiredService<ResourceDefinitionHitCounter>();
151152

152153
var settingsProvider = (TestClientSettingsProvider)_testContext.Factory.Services.GetRequiredService<IClientSettingsProvider>();
153-
settingsProvider.AutoIncludeOrbitingPlanetForMoons();
154+
settingsProvider.AutoIncludeStarGivingLightToMoon();
154155

155156
Planet planet = _fakers.Planet.Generate();
156157
planet.Moons = _fakers.Moon.Generate(1).ToHashSet();
157-
planet.Moons.ElementAt(0).OrbitsAround = _fakers.Planet.Generate();
158+
planet.Moons.ElementAt(0).IsGivenLightBy = _fakers.Star.Generate();
158159

159160
await _testContext.RunOnDatabaseAsync(async dbContext =>
160161
{
@@ -178,11 +179,9 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
178179
responseDocument.Included[0].Id.Should().Be(planet.Moons.ElementAt(0).StringId);
179180
responseDocument.Included[0].Attributes.ShouldContainKey("name").With(value => value.Should().Be(planet.Moons.ElementAt(0).Name));
180181

181-
string moonName = planet.Moons.ElementAt(0).OrbitsAround.PublicName;
182-
183-
responseDocument.Included[1].Type.Should().Be("planets");
184-
responseDocument.Included[1].Id.Should().Be(planet.Moons.ElementAt(0).OrbitsAround.StringId);
185-
responseDocument.Included[1].Attributes.ShouldContainKey("publicName").With(value => value.Should().Be(moonName));
182+
responseDocument.Included[1].Type.Should().Be("stars");
183+
responseDocument.Included[1].Id.Should().Be(planet.Moons.ElementAt(0).IsGivenLightBy!.StringId);
184+
responseDocument.Included[1].Attributes.ShouldContainKey("name").With(value => value.Should().Be(planet.Moons.ElementAt(0).IsGivenLightBy!.Name));
186185

187186
hitCounter.HitExtensibilityPoints.Should().BeEquivalentTo(new[]
188187
{
@@ -196,11 +195,14 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
196195
(typeof(Moon), ResourceDefinitionExtensibilityPoints.OnApplyPagination),
197196
(typeof(Moon), ResourceDefinitionExtensibilityPoints.OnApplySparseFieldSet),
198197
(typeof(Moon), ResourceDefinitionExtensibilityPoints.OnApplyIncludes),
199-
(typeof(Planet), ResourceDefinitionExtensibilityPoints.OnApplyIncludes),
198+
(typeof(Star), ResourceDefinitionExtensibilityPoints.OnApplySparseFieldSet),
199+
(typeof(Star), ResourceDefinitionExtensibilityPoints.OnApplyIncludes),
200200
(typeof(Planet), ResourceDefinitionExtensibilityPoints.OnApplySparseFieldSet),
201201
(typeof(Planet), ResourceDefinitionExtensibilityPoints.GetMeta),
202202
(typeof(Moon), ResourceDefinitionExtensibilityPoints.OnApplySparseFieldSet),
203-
(typeof(Moon), ResourceDefinitionExtensibilityPoints.GetMeta)
203+
(typeof(Moon), ResourceDefinitionExtensibilityPoints.GetMeta),
204+
(typeof(Star), ResourceDefinitionExtensibilityPoints.OnApplySparseFieldSet),
205+
(typeof(Star), ResourceDefinitionExtensibilityPoints.GetMeta)
204206
}, options => options.WithStrictOrdering());
205207
}
206208

Diff for: test/JsonApiDotNetCoreTests/IntegrationTests/ResourceDefinitions/Reading/TestClientSettingsProvider.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ internal sealed class TestClientSettingsProvider : IClientSettingsProvider
44
{
55
public bool IsIncludePlanetMoonsBlocked { get; private set; }
66
public bool ArePlanetsWithPrivateNameHidden { get; private set; }
7-
public bool IsMoonOrbitingPlanetAutoIncluded { get; private set; }
7+
public bool IsStarGivingLightToMoonAutoIncluded { get; private set; }
88

99
public void ResetToDefaults()
1010
{
1111
IsIncludePlanetMoonsBlocked = false;
1212
ArePlanetsWithPrivateNameHidden = false;
13-
IsMoonOrbitingPlanetAutoIncluded = false;
13+
IsStarGivingLightToMoonAutoIncluded = false;
1414
}
1515

1616
public void BlockIncludePlanetMoons()
@@ -23,8 +23,8 @@ public void HidePlanetsWithPrivateName()
2323
ArePlanetsWithPrivateNameHidden = true;
2424
}
2525

26-
public void AutoIncludeOrbitingPlanetForMoons()
26+
public void AutoIncludeStarGivingLightToMoon()
2727
{
28-
IsMoonOrbitingPlanetAutoIncluded = true;
28+
IsStarGivingLightToMoonAutoIncluded = true;
2929
}
3030
}

0 commit comments

Comments
 (0)