Skip to content

Commit 8bd3631

Browse files
Support facet on IEnumerable property
- Add methods for supporting facet for IEnumerable property - Add unit tests for feature
1 parent 1d5dc72 commit 8bd3631

File tree

4 files changed

+165
-11
lines changed

4 files changed

+165
-11
lines changed

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

+28-10
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,12 @@ public TypeQueryBuilder<T> Autocomplete(Expression<Func<T, object>> fieldSelecto
292292
}
293293
return this;
294294
}
295+
private void SetFacetClause(string facetClause)
296+
{
297+
graphObject.Facets = graphObject.Facets.IsNullOrEmpty() ?
298+
$"{facetClause}" :
299+
$"{graphObject.Facets} {facetClause}";
300+
}
295301
/// <summary>
296302
/// Get facet by field
297303
/// </summary>
@@ -324,9 +330,25 @@ public TypeQueryBuilder<T> Facet(Expression<Func<T, int>> fieldSelector)
324330
public TypeQueryBuilder<T> Facet(string propertyName)
325331
{
326332
string facet = ConvertNestedFieldToString.ConvertNestedFieldForFacet(propertyName);
327-
graphObject.Facets = graphObject.Facets.IsNullOrEmpty() ?
328-
$"{facet}" :
329-
$"{graphObject.Facets} {facet}";
333+
SetFacetClause(facet);
334+
return this;
335+
}
336+
public TypeQueryBuilder<T> Facet<TField>(Expression<Func<T, IEnumerable<TField>>> enumSelector, Expression<Func<TField, object>> fieldSelector)
337+
{
338+
enumSelector.ValidateNotNullArgument("enumSelector");
339+
fieldSelector.ValidateNotNullArgument("fieldSelector");
340+
var combinePath = $"{enumSelector.GetFieldPath()}.{fieldSelector.GetFieldPath()}";
341+
Facet(combinePath);
342+
return this;
343+
}
344+
public TypeQueryBuilder<T> Facet<TField>(Expression<Func<T, IEnumerable<TField>>> enumSelector, Expression<Func<TField, FacetFilter>> fieldSelector)
345+
{
346+
enumSelector.ValidateNotNullArgument("enumSelector");
347+
fieldSelector.ValidateNotNullArgument("fieldSelector");
348+
var parse = new FacetExpressionParser();
349+
var facetFilter = parse.GetFacetFilter(fieldSelector);
350+
351+
SetFacetClause($"{enumSelector.GetFieldPath()}{{{facetFilter.FilterClause}}}");
330352
return this;
331353
}
332354
public TypeQueryBuilder<T> Total(bool? isAll = null)
@@ -708,14 +730,12 @@ public TypeQueryBuilder<T> Where<TField>(string fieldPath, IFilterOperator filte
708730
Where(fieldPath, filterOperator);
709731
return this;
710732
}
711-
private TypeQueryBuilder<T> Facet(string propertyName, IFacetOperator facetFilter)
733+
public TypeQueryBuilder<T> Facet(string propertyName, IFacetOperator facetFilter)
712734
{
713735
propertyName.ValidateNotNullArgument("propertyName");
714736
facetFilter.ValidateNotNullArgument("facetFilter");
715737
string facets = ConvertNestedFieldToString.ConvertNestedFieldForFacet(propertyName, facetFilter);
716-
graphObject.Facets = graphObject.Facets.IsNullOrEmpty() ?
717-
$"{facets}" :
718-
$"{graphObject.Facets} {facets}";
738+
SetFacetClause(facets);
719739
return this;
720740
}
721741
public TypeQueryBuilder<T> Facet(Expression<Func<T, object>> fieldSelector, IFacetOperator facetFilter)
@@ -789,9 +809,7 @@ public TypeQueryBuilder<T> Facet(Expression<Func<T, DateTime?>> fieldSelector, D
789809
public TypeQueryBuilder<T> Facet(IFacetFilter facetFilter)
790810
{
791811
facetFilter.ValidateNotNullArgument("facetFilter");
792-
graphObject.Facets = graphObject.Facets.IsNullOrEmpty() ?
793-
$"{facetFilter.FilterClause}" :
794-
$"{graphObject.Facets} {facetFilter.FilterClause}";
812+
SetFacetClause(facetFilter.FilterClause);
795813
return this;
796814
}
797815
public TypeQueryBuilder<T> FilterForVisitor(params IFilterForVisitor[] filterForVisitors)

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

+54-1
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)));
@@ -66,5 +87,37 @@ public static DelegateFacetFilterBuilder FacetInRange(this IEnumerable<float> fi
6687
{
6788
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new NumericFacetFilterOperators().Ranges((from, to))));
6889
}
90+
public static DelegateFacetFilterBuilder FacetInRanges(this float field, params (float? from, float? to)[] ranges)
91+
{
92+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new NumericFacetFilterOperators().Ranges(ranges)));
93+
}
94+
public static DelegateFacetFilterBuilder FacetInRanges(this IEnumerable<float> field, params (float? from, float? to)[] ranges)
95+
{
96+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new NumericFacetFilterOperators().Ranges(ranges)));
97+
}
98+
public static DelegateFacetFilterBuilder FacetInRanges(this double field, params (double? from, double? to)[] ranges)
99+
{
100+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new NumericFacetFilterOperators().Ranges(ranges)));
101+
}
102+
public static DelegateFacetFilterBuilder FacetInRanges(this IEnumerable<double> field, params (double? from, double? to)[] ranges)
103+
{
104+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new NumericFacetFilterOperators().Ranges(ranges)));
105+
}
106+
public static DelegateFacetFilterBuilder FacetInRanges(this int field, params (int? from, int? to)[] ranges)
107+
{
108+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new NumericFacetFilterOperators().Ranges(ranges)));
109+
}
110+
public static DelegateFacetFilterBuilder FacetInRanges(this IEnumerable<int> field, params (int? from, int? to)[] ranges)
111+
{
112+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new NumericFacetFilterOperators().Ranges(ranges)));
113+
}
114+
public static DelegateFacetFilterBuilder FacetInRanges(this long field, params (long? from, long? to)[] ranges)
115+
{
116+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new NumericFacetFilterOperators().Ranges(ranges)));
117+
}
118+
public static DelegateFacetFilterBuilder FacetInRanges(this IEnumerable<long> field, params (long? from, long? to)[] ranges)
119+
{
120+
return new DelegateFacetFilterBuilder(field => new TermFacetFilter(field, new NumericFacetFilterOperators().Ranges(ranges)));
121+
}
69122
}
70123
}
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{NestedObjects{NestedProperty{name count}}}";
54+
const string expectedFullQuery = $"RequestTypeObject{{{expectedFields} {expectedFacet}}}";
55+
56+
typeQueryBuilder.Field(x => x.Property1);
57+
typeQueryBuilder.Facet(x => x.NestedObjects, 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{NestedObjects{NestedProperty(limit: 10){name count}}}";
70+
const string expectedFullQuery = $"RequestTypeObject{{{expectedFields} {expectedFacet}}}";
71+
72+
typeQueryBuilder.Field(x => x.Property1);
73+
typeQueryBuilder.Facet(x => x.NestedObjects, 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

+1
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)