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

Commit 0dd8957

Browse files
Support facet on IEnumerable property
- Add methods for supporting facet for IEnumerable property - Add unit tests for feature
1 parent a1f1f13 commit 0dd8957

File tree

4 files changed

+133
-11
lines changed

4 files changed

+133
-11
lines changed

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

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,12 @@ public TypeQueryBuilder<T> Autocomplete(Expression<Func<T, object>> fieldSelecto
271271
}
272272
return this;
273273
}
274+
private void SetFacetClause(string facetClause)
275+
{
276+
graphObject.Facets = graphObject.Facets.IsNullOrEmpty() ?
277+
$"{facetClause}" :
278+
$"{graphObject.Facets} {facetClause}";
279+
}
274280
/// <summary>
275281
/// Get facet by field
276282
/// </summary>
@@ -303,9 +309,25 @@ public TypeQueryBuilder<T> Facet(Expression<Func<T, int>> fieldSelector)
303309
public TypeQueryBuilder<T> Facet(string propertyName)
304310
{
305311
string facet = ConvertNestedFieldToString.ConvertNestedFieldForFacet(propertyName);
306-
graphObject.Facets = graphObject.Facets.IsNullOrEmpty() ?
307-
$"{facet}" :
308-
$"{graphObject.Facets} {facet}";
312+
SetFacetClause(facet);
313+
return this;
314+
}
315+
public TypeQueryBuilder<T> Facet<TField>(Expression<Func<T, IEnumerable<TField>>> enumSelector, Expression<Func<TField, object>> fieldSelector)
316+
{
317+
enumSelector.ValidateNotNullArgument("enumSelector");
318+
fieldSelector.ValidateNotNullArgument("fieldSelector");
319+
var combinePath = $"{enumSelector.GetFieldPath()}.{fieldSelector.GetFieldPath()}";
320+
Facet(combinePath);
321+
return this;
322+
}
323+
public TypeQueryBuilder<T> Facet<TField>(Expression<Func<T, IEnumerable<TField>>> enumSelector, Expression<Func<TField, FacetFilter>> fieldSelector)
324+
{
325+
enumSelector.ValidateNotNullArgument("enumSelector");
326+
fieldSelector.ValidateNotNullArgument("fieldSelector");
327+
var parse = new FacetExpressionParser();
328+
var facetFilter = parse.GetFacetFilter(fieldSelector);
329+
330+
SetFacetClause($"{enumSelector.GetFieldPath()}{{{facetFilter.FilterClause}}}");
309331
return this;
310332
}
311333
public TypeQueryBuilder<T> Total(bool? isAll = null)
@@ -599,14 +621,12 @@ public TypeQueryBuilder<T> Where<TField>(string fieldPath, IFilterOperator filte
599621
Where(fieldPath, filterOperator);
600622
return this;
601623
}
602-
private TypeQueryBuilder<T> Facet(string propertyName, IFacetOperator facetFilter)
624+
public TypeQueryBuilder<T> Facet(string propertyName, IFacetOperator facetFilter)
603625
{
604626
propertyName.ValidateNotNullArgument("propertyName");
605627
facetFilter.ValidateNotNullArgument("facetFilter");
606628
string facets = ConvertNestedFieldToString.ConvertNestedFieldForFacet(propertyName, facetFilter);
607-
graphObject.Facets = graphObject.Facets.IsNullOrEmpty() ?
608-
$"{facets}" :
609-
$"{graphObject.Facets} {facets}";
629+
SetFacetClause(facets);
610630
return this;
611631
}
612632
public TypeQueryBuilder<T> Facet(Expression<Func<T, object>> fieldSelector, IFacetOperator facetFilter)
@@ -680,9 +700,7 @@ public TypeQueryBuilder<T> Facet(Expression<Func<T, DateTime?>> fieldSelector, D
680700
public TypeQueryBuilder<T> Facet(IFacetFilter facetFilter)
681701
{
682702
facetFilter.ValidateNotNullArgument("facetFilter");
683-
graphObject.Facets = graphObject.Facets.IsNullOrEmpty() ?
684-
$"{facetFilter.FilterClause}" :
685-
$"{graphObject.Facets} {facetFilter.FilterClause}";
703+
SetFacetClause(facetFilter.FilterClause);
686704
return this;
687705
}
688706
public TypeQueryBuilder<T> FilterForVisitor(params IFilterForVisitor[] filterForVisitors)

APIs/src/EpiServer.ContentGraph/Extensions/FacetExtension.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,31 @@ namespace EPiServer.ContentGraph.Extensions
55
{
66
public static class FacetExtension
77
{
8-
public static DelegateFacetFilterBuilder FacetLimit(this object field, int limit=5)
8+
public static DelegateFacetFilterBuilder FacetLimit(this object field, int limit = 5)
99
{
1010
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new StringFacetFilterOperators().Limit(limit)));
1111
}
12+
public static DelegateFacetFilterBuilder FacetLimit(this string field, int limit=5)
13+
{
14+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new StringFacetFilterOperators().Limit(limit)));
15+
}
16+
public static DelegateFacetFilterBuilder FacetLimit(this float field, int limit = 5)
17+
{
18+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new StringFacetFilterOperators().Limit(limit)));
19+
}
20+
public static DelegateFacetFilterBuilder FacetLimit(this double field, int limit = 5)
21+
{
22+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new StringFacetFilterOperators().Limit(limit)));
23+
}
24+
public static DelegateFacetFilterBuilder FacetLimit(this int field, int limit = 5)
25+
{
26+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new StringFacetFilterOperators().Limit(limit)));
27+
}
28+
public static DelegateFacetFilterBuilder FacetLimit(this bool field, int limit = 5)
29+
{
30+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new StringFacetFilterOperators().Limit(limit)));
31+
}
32+
1233
public static DelegateFacetFilterBuilder FacetFilters(this string field, params string[] values)
1334
{
1435
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new StringFacetFilterOperators().Filters(values)));
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using EPiServer.ContentGraph.Api.Querying;
2+
using EpiServer.ContentGraph.UnitTests.QueryTypeObjects;
3+
using Xunit;
4+
using EPiServer.ContentGraph.Extensions;
5+
6+
namespace EpiServer.ContentGraph.UnitTests.ExtensionTests
7+
{
8+
[CollectionDefinition("Facet extension tests")]
9+
public class FacetExtensionTests
10+
{
11+
TypeQueryBuilder<RequestTypeObject> typeQueryBuilder;
12+
public FacetExtensionTests()
13+
{
14+
typeQueryBuilder = new TypeQueryBuilder<RequestTypeObject>();
15+
}
16+
17+
[Fact]
18+
public void generate_facet_filter_with_extension()
19+
{
20+
const string expectedFields = "items{Property1}";
21+
const string expectedFacet = "facets{Property1(filters: [\"test\"]){name count}}";
22+
const string expectedFullQuery = $"RequestTypeObject{{{expectedFields} {expectedFacet}}}";
23+
24+
typeQueryBuilder.Field(x => x.Property1);
25+
typeQueryBuilder.Facet(x => x.Property1.FacetFilters("test"));
26+
27+
var query = typeQueryBuilder.ToQuery().GetQuery();
28+
29+
Assert.NotNull(query);
30+
Assert.Contains(expectedFacet, query.Query);
31+
Assert.Equal(query.Query, expectedFullQuery);
32+
}
33+
[Fact]
34+
public void generate_facet_limit_with_extension()
35+
{
36+
const string expectedFields = "items{Property1}";
37+
const string expectedFacet = "facets{Property1(limit: 10){name count}}";
38+
const string expectedFullQuery = $"RequestTypeObject{{{expectedFields} {expectedFacet}}}";
39+
40+
typeQueryBuilder.Field(x => x.Property1);
41+
typeQueryBuilder.Facet(x => x.Property1.FacetLimit(10));
42+
43+
var query = typeQueryBuilder.ToQuery().GetQuery();
44+
45+
Assert.NotNull(query);
46+
Assert.Contains(expectedFacet, query.Query);
47+
Assert.Equal(query.Query, expectedFullQuery);
48+
}
49+
[Fact]
50+
public void generate_facet_with_IEnumerable()
51+
{
52+
const string expectedFields = "items{Property1}";
53+
const string expectedFacet = "facets{Nesteds{NestedProperty{name count}}}";
54+
const string expectedFullQuery = $"RequestTypeObject{{{expectedFields} {expectedFacet}}}";
55+
56+
typeQueryBuilder.Field(x => x.Property1);
57+
typeQueryBuilder.Facet(x => x.Nesteds, f=> f.NestedProperty);
58+
59+
var query = typeQueryBuilder.ToQuery().GetQuery();
60+
61+
Assert.NotNull(query);
62+
Assert.Contains(expectedFacet, query.Query);
63+
Assert.Equal(query.Query, expectedFullQuery);
64+
}
65+
[Fact]
66+
public void generate_facet_limit_with_IEnumerable()
67+
{
68+
const string expectedFields = "items{Property1}";
69+
const string expectedFacet = "facets{Nesteds{NestedProperty(limit: 10){name count}}}";
70+
const string expectedFullQuery = $"RequestTypeObject{{{expectedFields} {expectedFacet}}}";
71+
72+
typeQueryBuilder.Field(x => x.Property1);
73+
typeQueryBuilder.Facet(x => x.Nesteds, f => f.NestedProperty.FacetLimit(10));
74+
75+
var query = typeQueryBuilder.ToQuery().GetQuery();
76+
77+
Assert.NotNull(query);
78+
Assert.Contains(expectedFacet, query.Query);
79+
Assert.Equal(query.Query, expectedFullQuery);
80+
}
81+
}
82+
}

APIs/src/Testing/EpiServer.ContentGraph.UnitTests/QueryTypeObjects/NestedObject.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
internal class NestedObject
44
{
55
public int NestedProperty { get; set; }
6+
public string NestedStringProperty { get; set; }
67
}
78
}

0 commit comments

Comments
 (0)