Skip to content
This repository was archived by the owner on Aug 25, 2025. It is now read-only.

Commit 842fded

Browse files
FIND-13339: Cyclic queries
- Update BaseTypeQueryBuilder & FragmentBuilder to allow cyclic fragment
1 parent 96d4d2d commit 842fded

File tree

5 files changed

+62
-10
lines changed

5 files changed

+62
-10
lines changed

APIs/src/EpiServer.ContentGraph/Api/Querying/BaseTypeQueryBuilder.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,15 @@ private IEnumerable<FragmentBuilder> GetAllChildren(FragmentBuilder fragment)
206206
{
207207
foreach (var child in fragment.ChildrenFragments)
208208
{
209-
yield return child;
209+
if (Parent.HasFragment(child.GetName()))
210+
{
211+
continue;
212+
}
213+
else
214+
{
215+
yield return child;
216+
}
217+
210218
if (child.HasChildren)
211219
{
212220
foreach (var item in GetAllChildren(child))

APIs/src/EpiServer.ContentGraph/Api/Querying/FragmentBuilder.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,9 @@ public override FragmentBuilder AddFragments(params FragmentBuilder[] fragments)
6060
}
6161
return this;
6262
}
63-
public FragmentBuilder AddFragment(string path, FragmentBuilder fragment)
63+
public override FragmentBuilder AddFragment(string path, FragmentBuilder fragment)
6464
{
65-
if (_childrenFragments.IsNull())
66-
{
67-
_childrenFragments = new List<FragmentBuilder>();
68-
}
65+
_childrenFragments ??= new List<FragmentBuilder>();
6966
base.AddFragment(path, fragment);
7067
_childrenFragments.Add(fragment);
7168

APIs/src/EpiServer.ContentGraph/Api/Querying/GraphQueryBuilder.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,7 @@ public void AddFragment(FragmentBuilder fragmentBuilder)
9898
{
9999
_fragmentBuilders = new Dictionary<string, FragmentBuilder>();
100100
}
101-
if (!_fragmentBuilders.TryAdd(fragmentBuilder.GetName(), fragmentBuilder))
102-
{
103-
throw new ArgumentException($"Fragment [{fragmentBuilder.GetName()}] had added already.");
104-
}
101+
_fragmentBuilders.TryAdd(fragmentBuilder.GetName(), fragmentBuilder);
105102
}
106103
public IEnumerable<FragmentBuilder> GetFragments()
107104
{
@@ -328,5 +325,10 @@ public void AddQuery(string typeQuery)
328325
{
329326
typeQueries.Add(typeQuery);
330327
}
328+
329+
public bool HasFragment(string fragmentName)
330+
{
331+
return _fragmentBuilders.ContainsKey(fragmentName);
332+
}
331333
}
332334
}

APIs/src/EpiServer.ContentGraph/Api/Querying/IQuery.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public interface IQuery
88
public Task<ContentGraphResult<TResult>> GetResultAsync<TResult>();
99
public Task<ContentGraphResult> GetResultAsync();
1010
internal void AddFragment(FragmentBuilder fragmentBuilder);
11+
internal bool HasFragment(string fragmentName);
1112
internal void AddQuery(string typeQuery);
1213
}
1314
}

APIs/src/Testing/EpiServer.ContentGraph.UnitTests/GenerateFragmentTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,5 +225,49 @@ public void fragment_on_field_should_generate_correct_query()
225225
//expect full query
226226
Assert.Equal(expectedFullQuery, graphQueryBuilder.GetQuery().Query);
227227
}
228+
[Fact]
229+
public void cyclic_fragments_should_generate_correct_query()
230+
{
231+
const string expectedMainQuery = "query FragmentTest {FragmentObject{items{Name ...FirstFragment ...SecondFragment}}}";
232+
const string expectedFistFragment = "fragment FirstFragment on PromoExtend {ProviderName Details{PromoImage{PromoExtend{...FirstFragment}}}}";
233+
const string expectedSecondFragmment = "fragment SecondFragment on PromoObject {Url PromoExtend{...ThirdFragment}}";
234+
const string expectedThirdFragmment = "fragment ThirdFragment on PromoExtend {ProviderName PromoExtend{...SecondFragment}}";
235+
const string expectedFullQuery = $"{expectedMainQuery}\n{expectedFistFragment}\n{expectedSecondFragmment}\n{expectedThirdFragmment}";
236+
//Self-referenced query: a -> a
237+
var firstFragment = new FragmentBuilder<PromoExtend>("FirstFragment");
238+
firstFragment.Fields(x => x.ProviderName);
239+
firstFragment.AddFragment(x => x.Details.PromoImage.PromoExtend, firstFragment);
240+
241+
Assert.Equal(firstFragment.GetQuery().Query, expectedFistFragment);
242+
243+
//Cross-referenced: a -> b -> a
244+
var secondFragment = new FragmentBuilder<PromoObject>("SecondFragment");
245+
secondFragment.Fields(x => x.Url);
246+
247+
var thirdFragment = new FragmentBuilder<PromoExtend>("ThirdFragment");
248+
thirdFragment.Fields(x => x.ProviderName);
249+
250+
secondFragment.AddFragment(x => x.PromoExtend, thirdFragment);
251+
thirdFragment.AddFragment(x=> x.PromoExtend, secondFragment);
252+
253+
Assert.Equal(secondFragment.GetQuery().Query, expectedSecondFragmment);
254+
Assert.Equal(thirdFragment.GetQuery().Query, expectedThirdFragmment);
255+
256+
GraphQueryBuilder graphQueryBuilder = new GraphQueryBuilder();
257+
graphQueryBuilder
258+
.OperationName("FragmentTest")
259+
.ForType<FragmentObject>()
260+
.Field(x => x.Name)
261+
.AddFragments(firstFragment, secondFragment)
262+
.ToQuery()
263+
.BuildQueries();
264+
265+
Assert.Equal(graphQueryBuilder.GetFragments().First().GetQuery().Query, expectedFistFragment);
266+
Assert.Equal(graphQueryBuilder.GetFragments().Skip(1).First().GetQuery().Query, expectedSecondFragmment);
267+
Assert.Equal(graphQueryBuilder.GetFragments().Last().GetQuery().Query, expectedThirdFragmment);
268+
269+
//expect full query
270+
Assert.Equal(expectedFullQuery, graphQueryBuilder.GetQuery().Query);
271+
}
228272
}
229273
}

0 commit comments

Comments
 (0)