Skip to content
This repository was archived by the owner on Aug 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,7 @@ public virtual BaseTypeQueryBuilder Field(string propertyName)
if (!propertyName.IsNullOrEmpty())
{
string clonedPropName = ConvertNestedFieldToString.ConvertNestedFieldForQuery(propertyName);
graphObject.SelectItems.Append(
graphObject.SelectItems.Length == 0 ?
$"{clonedPropName}" :
$" {clonedPropName}"
);
AppendItem(clonedPropName);
}

return this;
Expand All @@ -72,11 +68,7 @@ public virtual BaseTypeQueryBuilder Field(string propertyName, string alias)
if (!propertyName.IsNullOrEmpty() && !alias.IsNullOrEmpty())
{
string clonedPropName = ConvertNestedFieldToString.ConvertNestedFieldForQuery(propertyName);
graphObject.SelectItems.Append(
graphObject.SelectItems.Length == 0 ?
$"{alias}:{clonedPropName}" :
$" {alias}:{clonedPropName}"
);
AppendItem($"{alias}:{clonedPropName}");
}
else
{
Expand All @@ -97,11 +89,7 @@ public virtual BaseTypeQueryBuilder Field(string propertyName, HighLightOptions
return this;
}
string clonedPropName = ConvertNestedFieldToString.ConvertNestedFieldForQuery(propertyName);
graphObject.SelectItems.Append(
graphObject.SelectItems.Length == 0 ?
$"{clonedPropName}{highLightOptions.Query}" :
$" {clonedPropName}{highLightOptions.Query}"
);
AppendItem($"{clonedPropName}{highLightOptions.Query}");
}

return this;
Expand All @@ -119,17 +107,9 @@ public virtual BaseTypeQueryBuilder Link(ITypeQueryBuilder link)
{
if (!linkQueryBuilder.GetLinkType().IsNullOrEmpty())
{
graphObject.SelectItems.Append(
graphObject.SelectItems.Length == 0 ?
$"_link(type:{linkQueryBuilder.GetLinkType()})" :
$" _link(type:{linkQueryBuilder.GetLinkType()})"
);
AppendItem($"_link(type:{linkQueryBuilder.GetLinkType()})");
}
graphObject.SelectItems.Append(
graphObject.SelectItems.Length == 0 ?
$"{{{linkQuery}}}" :
$" {{{linkQuery}}}"
);
AppendItem($"{{{linkQuery}}}");
}
return this;
}
Expand All @@ -152,27 +132,15 @@ public virtual BaseTypeQueryBuilder Link(ITypeQueryBuilder link, string alias)
{
if (string.IsNullOrEmpty(alias))
{
graphObject.SelectItems.Append(
graphObject.SelectItems.Length == 0 ?
$"_link(type:{linkQueryBuilder.GetLinkType()})" :
$" _link(type:{linkQueryBuilder.GetLinkType()})"
);
AppendItem($"_link(type:{linkQueryBuilder.GetLinkType()})");
}
else
{
graphObject.SelectItems.Append(
graphObject.SelectItems.Length == 0 ?
$"{alias}:_link(type:{linkQueryBuilder.GetLinkType()})" :
$" {alias}:_link(type:{linkQueryBuilder.GetLinkType()})"
);
AppendItem($"{alias}:_link(type:{linkQueryBuilder.GetLinkType()})");
}

}
graphObject.SelectItems.Append(
graphObject.SelectItems.Length == 0 ?
$"{{{linkQuery}}}" :
$" {{{linkQuery}}}"
);
AppendItem($"{{{linkQuery}}}");

}
return this;
Expand All @@ -184,11 +152,7 @@ public virtual BaseTypeQueryBuilder Children(ITypeQueryBuilder children)
string childrenItems = children.GetQuery()?.Query ?? string.Empty;
if (!childrenItems.IsNullOrEmpty())
{
graphObject.SelectItems.Append(
graphObject.SelectItems.Length == 0 ?
$"_children{{{childrenItems}}}" :
$" _children{{{childrenItems}}}"
);
AppendItem($"_children{{{childrenItems}}}");
}

return this;
Expand All @@ -203,13 +167,27 @@ public virtual BaseTypeQueryBuilder AddFragments(params FragmentBuilder[] fragme
return this;
}
protected virtual BaseTypeQueryBuilder AddFragment(FragmentBuilder fragment)
{
AddFragment(null, fragment);
return this;
}
public virtual BaseTypeQueryBuilder AddFragment(string fieldPath, FragmentBuilder fragment)
{
fragment.ValidateNotNullArgument("fragment");
graphObject.SelectItems.Append(
graphObject.SelectItems.Length == 0 ?
$"...{fragment.GetName()}" :
$" ...{fragment.GetName()}"
);
string propName;
if (fieldPath.IsNullOrEmpty())
{
propName = $"...{fragment.GetName()}";
}
else
{
var newPath = $"{fieldPath}.$$${fragment.GetName()}";
//trick: fragment init by $$$ then replace by dots ...
propName = ConvertNestedFieldToString.ConvertNestedFieldForQuery(newPath);
propName = propName.Replace("$", ".");
}

AppendItem(propName);

if (Parent != null)
{
Expand Down Expand Up @@ -239,5 +217,13 @@ private IEnumerable<FragmentBuilder> GetAllChildren(FragmentBuilder fragment)
}
}
}

protected virtual void AppendItem(string item)
{
if (!item.IsNullOrEmpty())
{
graphObject.SelectItems.Append(graphObject.SelectItems.Length > 0 ? $" {item}": item);
}
}
}
}
35 changes: 23 additions & 12 deletions APIs/src/EpiServer.ContentGraph/Api/Querying/FragmentBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ public override FragmentBuilder AddFragments(params FragmentBuilder[] fragments)
}
return this;
}
public FragmentBuilder AddFragment(string path, FragmentBuilder fragment)
{
if (_childrenFragments.IsNull())
{
_childrenFragments = new List<FragmentBuilder>();
}
base.AddFragment(path, fragment);
_childrenFragments.Add(fragment);

return this;
}
}

public class FragmentBuilder<T> : FragmentBuilder
Expand Down Expand Up @@ -112,10 +123,7 @@ private FragmentBuilder Recursive<TSub>(params Recursion[] recursives) where TSu
}

string subTypeName = typeof(TSub).Name;
graphObject.SelectItems.Append(graphObject.SelectItems.Length == 0 ?
$"... on {subTypeName}{{{recursiveNess}}}" :
$" ... on {subTypeName}{{{recursiveNess}}}"
);
AppendItem($"... on {subTypeName}{{{recursiveNess}}}");
return this;
}
private FragmentBuilder<T> Recursive<TSub>(string fieldName, int? depth = null) where TSub : T
Expand Down Expand Up @@ -154,10 +162,7 @@ public FragmentBuilder<T> Inline<TSub>(params string[] fields)
propertyBuilder.Append(ConvertNestedFieldToString.ConvertNestedFieldForQuery(field));
}
string subTypeName = typeof(TSub).Name;
graphObject.SelectItems.Append(graphObject.SelectItems.Length == 0 ?
$"... on {subTypeName}{{{propertyBuilder}}}" :
$" ... on {subTypeName}{{{propertyBuilder}}}"
);
AppendItem($"... on {subTypeName}{{{propertyBuilder}}}");
return this;
}
/// <summary>
Expand All @@ -179,10 +184,7 @@ public FragmentBuilder<T> Inline<TSub>(params Expression<Func<TSub, object>>[] f
propertyBuilder.Append(ConvertNestedFieldToString.ConvertNestedFieldForQuery(fieldSelector.GetFieldPath()));
}
string subTypeName = typeof(TSub).Name;
graphObject.SelectItems.Append(graphObject.SelectItems.Length == 0 ?
$"... on {subTypeName}{{{propertyBuilder}}}" :
$" ... on {subTypeName}{{{propertyBuilder}}}"
);
AppendItem($"... on {subTypeName}{{{propertyBuilder}}}");
return this;
}
/// <summary>
Expand All @@ -198,6 +200,15 @@ public FragmentBuilder<T> Inline<TSub>(params Expression<Func<TSub, Recursion>>[
Recursive<TSub>(fieldSelectors.Select(selector => paser.GetReturnType(selector)).ToArray());
return this;
}
public FragmentBuilder<T> AddFragment<TProp>(Expression<Func<T, TProp>> fieldSelector, FragmentBuilder<TProp> fragment)
{
fieldSelector.ValidateNotNullArgument(nameof(fieldSelector));
fragment.ValidateNotNullArgument(nameof(fragment));

var fieldPath = fieldSelector.GetFieldPath();
base.AddFragment(fieldPath, fragment);
return this;
}
public override GraphQLRequest GetQuery()
{
_query.Query = $"fragment {_query.OperationName} on {typeof(T).Name} {graphObject}";
Expand Down
45 changes: 17 additions & 28 deletions APIs/src/EpiServer.ContentGraph/Api/Querying/TypeQueryBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ protected override TypeQueryBuilder<T> AddFragment(FragmentBuilder fragment)
base.AddFragment(fragment);
return this;
}
public TypeQueryBuilder<T> AddFragment<TProp>(Expression<Func<T, TProp>> fieldSelector, FragmentBuilder<TProp> fragment)
{
fieldSelector.ValidateNotNullArgument(nameof(fieldSelector));
fragment.ValidateNotNullArgument(nameof(fragment));

var fieldPath = fieldSelector.GetFieldPath();
base.AddFragment(fieldPath, fragment);
return this;
}

public override TypeQueryBuilder<T> Field(string propertyName)
{
base.Field(propertyName);
Expand Down Expand Up @@ -146,10 +156,7 @@ public TypeQueryBuilder<T> NestedFields<TField>(Expression<Func<T, IEnumerable<T
public TypeQueryBuilder<T> AsType<TSub>(string propertyName) where TSub : T
{
string subTypeName = typeof(TSub).Name;
graphObject.SelectItems.Append(graphObject.SelectItems.Length == 0 ?
$"... on {subTypeName}{{{ConvertNestedFieldToString.ConvertNestedFieldForQuery(propertyName)}}}" :
$" ... on {subTypeName}{{{ConvertNestedFieldToString.ConvertNestedFieldForQuery(propertyName)}}}"
);
AppendItem($"... on {subTypeName}{{{ConvertNestedFieldToString.ConvertNestedFieldForQuery(propertyName)}}}");
return this;
}
[Obsolete("Obsoleted. Use InlineFragment instead")]
Expand All @@ -173,10 +180,7 @@ public TypeQueryBuilder<T> AsType<TSub>(params Expression<Func<TSub, object>>[]

}
string subTypeName = typeof(TSub).Name;
graphObject.SelectItems.Append(graphObject.SelectItems.Length == 0 ?
$"... on {subTypeName}{{{propertyName}}}" :
$" ... on {subTypeName}{{{propertyName}}}"
);
AppendItem($"... on {subTypeName}{{{propertyName}}}");
return this;
}
[Obsolete("Obsoleted. Use InlineFragment instead")]
Expand All @@ -191,10 +195,7 @@ public TypeQueryBuilder<T> AsType<TSub>(SubTypeQueryBuilder<TSub> subTypeQuery)
subTypeQuery.ValidateNotNullArgument("subTypeQuery");
subTypeQuery.Parent = this.Parent;
string subTypeName = typeof(TSub).Name;
graphObject.SelectItems.Append(graphObject.SelectItems.Length == 0 ?
$"... on {subTypeName}{subTypeQuery.GetQuery().Query}" :
$" ... on {subTypeName}{subTypeQuery.GetQuery().Query}"
);
AppendItem($"... on {subTypeName}{subTypeQuery.GetQuery().Query}");
return this;
}
public TypeQueryBuilder<T> InlineFragment<TSub>(params Expression<Func<TSub, string>>[] fieldSelectors) where TSub : T
Expand All @@ -211,10 +212,7 @@ public TypeQueryBuilder<T> InlineFragment<TSub>(params Expression<Func<TSub, str

}
string subTypeName = typeof(TSub).Name;
graphObject.SelectItems.Append(graphObject.SelectItems.Length == 0 ?
$"... on {subTypeName}{{{propertyName}}}" :
$" ... on {subTypeName}{{{propertyName}}}"
);
AppendItem($"... on {subTypeName}{{{propertyName}}}");
return this;
}
public TypeQueryBuilder<T> InlineFragment<TSub>(params Expression<Func<TSub, int>>[] fieldSelectors) where TSub : T
Expand All @@ -231,10 +229,7 @@ public TypeQueryBuilder<T> InlineFragment<TSub>(params Expression<Func<TSub, int

}
string subTypeName = typeof(TSub).Name;
graphObject.SelectItems.Append(graphObject.SelectItems.Length == 0 ?
$"... on {subTypeName}{{{propertyName}}}" :
$" ... on {subTypeName}{{{propertyName}}}"
);
AppendItem($"... on {subTypeName}{{{propertyName}}}");
return this;
}
public TypeQueryBuilder<T> InlineFragment<TSub>(params Expression<Func<TSub, double>>[] fieldSelectors) where TSub : T
Expand All @@ -251,10 +246,7 @@ public TypeQueryBuilder<T> InlineFragment<TSub>(params Expression<Func<TSub, dou

}
string subTypeName = typeof(TSub).Name;
graphObject.SelectItems.Append(graphObject.SelectItems.Length == 0 ?
$"... on {subTypeName}{{{propertyName}}}" :
$" ... on {subTypeName}{{{propertyName}}}"
);
AppendItem($"... on {subTypeName}{{{propertyName}}}");
return this;
}
public TypeQueryBuilder<T> InlineFragment<TSub>(params Expression<Func<TSub, IEnumerable<string>>>[] fieldSelectors) where TSub : T
Expand All @@ -271,10 +263,7 @@ public TypeQueryBuilder<T> InlineFragment<TSub>(params Expression<Func<TSub, IEn

}
string subTypeName = typeof(TSub).Name;
graphObject.SelectItems.Append(graphObject.SelectItems.Length == 0 ?
$"... on {subTypeName}{{{propertyName}}}" :
$" ... on {subTypeName}{{{propertyName}}}"
);
AppendItem($"... on {subTypeName}{{{propertyName}}}");
return this;
}
public TypeQueryBuilder<T> Autocomplete(Expression<Func<T, object>> fieldSelector, AutoCompleteOperators autocomplete)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,5 +189,41 @@ public void fragment_with_single_recursive_should_generate_correct_query()
//expect full query
Assert.Equal(expectedFullQuery, graphQueryBuilder.GetQuery().Query);
}

[Fact]
public void fragment_on_field_should_generate_correct_query()
{
const string expectedMainQuery = "query FragmentTest {FragmentObject{items{Name PromoImage{...SecondFragment}}}}";
const string expectedFistFragment = "fragment FirstFragment on PromoExtend {ProviderName}";
const string expectedSecondFragmment = "fragment SecondFragment on PromoObject {Url PromoExtend{...FirstFragment}}";
const string expectedFullQuery = $"{expectedMainQuery}\n{expectedSecondFragmment}\n{expectedFistFragment}";

var firstFragment = new FragmentBuilder<PromoExtend>("FirstFragment");
firstFragment.Fields(x => x.ProviderName);

Assert.Equal(firstFragment.GetQuery().Query, expectedFistFragment);

var secondFragment = new FragmentBuilder<PromoObject>("SecondFragment");
secondFragment.Fields(x => x.Url);
secondFragment.AddFragment(x => x.PromoExtend, firstFragment);

GraphQueryBuilder graphQueryBuilder = new GraphQueryBuilder();
graphQueryBuilder
.OperationName("FragmentTest")
.ForType<FragmentObject>()
.Field(x => x.Name)
.AddFragment(x=> x.PromoImage, secondFragment)
.ToQuery()
.BuildQueries();

//expect children in secondary fragment
Assert.Equal(graphQueryBuilder.GetFragments().First().GetName(), "SecondFragment");
Assert.True(graphQueryBuilder.GetFragments().First().HasChildren);
Assert.Equal(graphQueryBuilder.GetFragments().First().ChildrenFragments.First().GetQuery().Query, expectedFistFragment);
//expect secondary fragment
Assert.Equal(graphQueryBuilder.GetFragments().First().GetQuery().Query, expectedSecondFragmment);
//expect full query
Assert.Equal(expectedFullQuery, graphQueryBuilder.GetQuery().Query);
}
}
}
Loading