Skip to content

Commit e9db0de

Browse files
FIND-12398: Add Highlight to the query
- Add highlight options to TypeQueryBuilder and SubTypeQueryBuilder - Move Field with alias to base class for reuse
1 parent 7d575bb commit e9db0de

File tree

8 files changed

+182
-2
lines changed

8 files changed

+182
-2
lines changed

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

+41
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,47 @@ public virtual BaseTypeQueryBuilder Field(string propertyName)
6565

6666
return this;
6767
}
68+
public virtual BaseTypeQueryBuilder Field(string propertyName, string alias)
69+
{
70+
propertyName.ValidateNotNullArgument("propertyName");
71+
alias.ValidateNotNullArgument("alias");
72+
if (!propertyName.IsNullOrEmpty() && !alias.IsNullOrEmpty())
73+
{
74+
string clonedPropName = ConvertNestedFieldToString.ConvertNestedFieldForQuery(propertyName);
75+
graphObject.SelectItems.Append(
76+
graphObject.SelectItems.Length == 0 ?
77+
$"{alias}:{clonedPropName}" :
78+
$" {alias}:{clonedPropName}"
79+
);
80+
}
81+
else
82+
{
83+
Field(propertyName);
84+
}
85+
86+
return this;
87+
}
88+
public virtual BaseTypeQueryBuilder Field(string propertyName, HighLightOptions highLightOptions)
89+
{
90+
propertyName.ValidateNotNullArgument("propertyName");
91+
92+
if (!propertyName.IsNullOrEmpty())
93+
{
94+
if (highLightOptions.IsNull())
95+
{
96+
Field(propertyName);
97+
return this;
98+
}
99+
string clonedPropName = ConvertNestedFieldToString.ConvertNestedFieldForQuery(propertyName);
100+
graphObject.SelectItems.Append(
101+
graphObject.SelectItems.Length == 0 ?
102+
$"{clonedPropName}{highLightOptions.Query}" :
103+
$" {clonedPropName}{highLightOptions.Query}"
104+
);
105+
}
106+
107+
return this;
108+
}
68109
public virtual BaseTypeQueryBuilder Link(ITypeQueryBuilder link)
69110
{
70111
link.ValidateNotNullArgument("link");

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

+6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ private FragmentBuilder<T> Field(Expression<Func<T, object>> fieldSelector)
2020
base.Field(fieldSelector.GetFieldPath());
2121
return this;
2222
}
23+
public FragmentBuilder<T> Field(Expression<Func<T, object>> fieldSelector, string alias)
24+
{
25+
fieldSelector.ValidateNotNullArgument("fieldSelector");
26+
base.Field(fieldSelector.GetFieldPath(), alias);
27+
return this;
28+
}
2329
public FragmentBuilder<T> Fields(params Expression<Func<T, object>>[] fieldSelectors)
2430
{
2531
fieldSelectors.ValidateNotNullArgument("fieldSelectors");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using EPiServer.ContentGraph.Helpers.Text;
2+
namespace EPiServer.ContentGraph.Api.Querying
3+
{
4+
public class HighLightOptions
5+
{
6+
public static HighLightOptions Create()
7+
{
8+
return new HighLightOptions();
9+
}
10+
string _query = string.Empty;
11+
public string Query => $"(highlight:{{{_query}}})";
12+
13+
public HighLightOptions StartToken(string token)
14+
{
15+
_query += _query.IsNullOrEmpty() ? $"startToken:\"{token}\"" : $",startToken:\"{token}\"";
16+
return this;
17+
}
18+
public HighLightOptions EndToken(string token)
19+
{
20+
_query += _query.IsNullOrEmpty() ? $"endToken:\"{token}\"" : $",endToken:\"{token}\"";
21+
return this;
22+
}
23+
public HighLightOptions Enable(bool enable)
24+
{
25+
_query += _query.IsNullOrEmpty() ? $"enabled:{enable.ToString().ToLower()}" : $",enabled:{enable.ToString().ToLower()}";
26+
return this;
27+
}
28+
}
29+
}

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

+21
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,27 @@ public SubTypeQueryBuilder<T> Field(Expression<Func<T, object>> fieldSelector)
2727
base.Field(fieldSelector.GetFieldPath());
2828
return this;
2929
}
30+
public SubTypeQueryBuilder<T> Field(Expression<Func<T, object>> fieldSelector, string alias)
31+
{
32+
fieldSelector.ValidateNotNullArgument("fieldSelector");
33+
var propertyName = fieldSelector.GetFieldPath();
34+
base.Field(propertyName, alias);
35+
return this;
36+
}
37+
public SubTypeQueryBuilder<T> Field(Expression<Func<T, object>> fieldSelector, HighLightOptions highLightOptions, string alias = "")
38+
{
39+
fieldSelector.ValidateNotNullArgument("fieldSelector");
40+
var propertyName = fieldSelector.GetFieldPath();
41+
if (string.IsNullOrEmpty(alias))
42+
{
43+
base.Field($"{propertyName}", highLightOptions);
44+
}
45+
else
46+
{
47+
base.Field($"{alias}:{propertyName}", highLightOptions);
48+
}
49+
return this;
50+
}
3051
public SubTypeQueryBuilder<T> Fields(params Expression<Func<T, object>>[] fieldSelectors)
3152
{
3253
fieldSelectors.ValidateNotNullArgument("fieldSelectors");

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

+15-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,21 @@ public TypeQueryBuilder<T> Field(Expression<Func<T, object>> fieldSelector, stri
7777
{
7878
fieldSelector.ValidateNotNullArgument("fieldSelector");
7979
var propertyName = fieldSelector.GetFieldPath();
80-
Field($"{alias}:{propertyName}");
80+
base.Field(propertyName, alias);
81+
return this;
82+
}
83+
public TypeQueryBuilder<T> Field(Expression<Func<T, object>> fieldSelector, HighLightOptions highLightOptions, string alias = "")
84+
{
85+
fieldSelector.ValidateNotNullArgument("fieldSelector");
86+
var propertyName = fieldSelector.GetFieldPath();
87+
if (string.IsNullOrEmpty(alias))
88+
{
89+
Field($"{propertyName}", highLightOptions);
90+
}
91+
else
92+
{
93+
Field($"{alias}:{propertyName}", highLightOptions);
94+
}
8195
return this;
8296
}
8397
public TypeQueryBuilder<T> Fields(params Expression<Func<T, object>>[] fieldSelectors)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using EPiServer.ContentGraph.Api.Querying;
2+
using EPiServer.ContentGraph.Extensions;
3+
using EPiServer.ContentGraph.IntegrationTests.TestModels;
4+
using EPiServer.ContentGraph.IntegrationTests.TestSupport;
5+
using Microsoft.VisualStudio.TestTools.UnitTesting;
6+
7+
namespace EPiServer.ContentGraph.IntegrationTests.QueryTests
8+
{
9+
[TestClass]
10+
public class HightLightingTests : IntegrationFixture
11+
{
12+
[ClassInitialize]
13+
public static void ClassInitialize(TestContext testContext)
14+
{
15+
var item1 = TestDataCreator.generateIndexActionJson("1", "en", new IndexActionData
16+
{
17+
ContentType = new[] { "Content","HomePage" },
18+
TypeName = "HomePage",
19+
Id = "content1",
20+
NameSearchable = "Action Movie",
21+
MainBodySearchable = "Wild Wild West is a 1999 American steampunk Western film co-produced and directed by Barry Sonnenfeld and written by S. S. Wilson and Brent Maddock alongside Jeffrey Price and Peter S. Seaman, from a story penned by brothers Jim and John Thomas. Loosely adapted from The Wild Wild West, a 1960s television series created by Michael Garrison, it is the only production since the television film More Wild Wild West (1980) to feature the characters from the original series. The film stars Will Smith (who previously collaborated with Sonnenfeld on Men in Black two years earlier in 1997) and Kevin Kline as two U.S. Secret Service agents who work together to protect U.S. President Ulysses S. Grant (Kline, in a dual role) and the United States from all manner of dangerous threats during the American Old West.",
22+
Priority = 100,
23+
IsSecret = true,
24+
Status = TestDataCreator.STATUS_PUBLISHED,
25+
RolesWithReadAccess = TestDataCreator.ROLES_EVERYONE
26+
});
27+
28+
SetupData<HomePage>(item1);
29+
}
30+
[TestMethod]
31+
public void search_data_with_highlight_should_result_wrap_keyword_in_tag()
32+
{
33+
IQuery query = new GraphQueryBuilder(_configOptions, _httpClientFactory)
34+
.ForType<HomePage>()
35+
.Field(x => x.MainBody, HighLightOptions.Create().Enable(true))
36+
.Where(x=> x.MainBody.Match("American"))
37+
.ToQuery()
38+
.BuildQueries();
39+
40+
var rs = query.GetResultAsync<HomePage>().Result;
41+
Assert.IsTrue(rs.Content.Hits.First().MainBody.Contains("<em>American</em>"));
42+
}
43+
}
44+
}

APIs/src/Testing/EPiServer.ContentGraph.IntegrationTests/TestSupport/IntegrationFixture.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ private static bool CountDoc<T>()
201201
return false;
202202
}
203203
}
204-
protected static void SetupData<T>(string indexingData, string testId)
204+
protected static void SetupData<T>(string indexingData, string testId="test")
205205
{
206206
string path = $@"{WorkingDirectory}\TestingData\SimpleTypeMapping.json";
207207
using (StreamReader mappingReader = new StreamReader(path))

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

+25
Original file line numberDiff line numberDiff line change
@@ -222,5 +222,30 @@ public void ChildrenQueryTests()
222222
Assert.Contains(expectedFields, query.GetQuery().Query);
223223
Assert.Equal($"RequestTypeObject{{{expectedFields} {expectedFacets}}}", query.GetQuery().Query);
224224
}
225+
[Fact]
226+
public void query_with_highlight_should_generate_correctly()
227+
{
228+
string expectedQuery1 = "RequestTypeObject(where:{Property1:{eq: \"test\"}}){items{Property1(highlight:{enabled:true})}}";
229+
string expectedQuery2 = "SubTypeObject(where:{Property2:{eq: 100}}){items{Property2(highlight:{enabled:true,startToken:\"a\",endToken:\"z\"})}}";
230+
string expectedFullQuery = $"query myquery {{{expectedQuery1} {expectedQuery2}}}";
231+
GraphQueryBuilder graphQueryBuilder = new GraphQueryBuilder();
232+
for (int i = 0; i < 2; i++)
233+
{
234+
graphQueryBuilder
235+
.OperationName("myquery")
236+
.ForType<RequestTypeObject>()
237+
.Field(x => x.Property1,HighLightOptions.Create().Enable(true))
238+
.Where(x => x.Property1, new StringFilterOperators().Eq("test"))
239+
.ToQuery()
240+
.ForType<SubTypeObject>()
241+
.Field(x => x.Property2, HighLightOptions.Create().Enable(true).StartToken("a").EndToken("z"))
242+
.Where(x => x.Property2, new NumericFilterOperators().Eq(100))
243+
.ToQuery()
244+
.BuildQueries();
245+
}
246+
247+
var query = graphQueryBuilder.GetQuery();
248+
Assert.Equal(expectedFullQuery, query.Query);
249+
}
225250
}
226251
}

0 commit comments

Comments
 (0)