Skip to content
Open
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
86 changes: 86 additions & 0 deletions src/Constructorio_NET.Tests/client/modules/AutocompleteTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,92 @@ public async Task GetAutocompleteResultsShouldReturnResultWithMultipleFilters()
Assert.GreaterOrEqual(res.Sections["Products"].Count, 1, "Results exist");
}

[Test]
public async Task GetAutocompleteResultsShouldReturnResultWithPreFilterExpression()
{
ValuePreFilterExpression filterByGroupId = new ValuePreFilterExpression("group_id", "All");
AutocompleteRequest req = new AutocompleteRequest("item")
{
UserInfo = UserInfo,
PreFilterExpression = filterByGroupId,
};
ConstructorIO constructorio = new ConstructorIO(this.Config);
AutocompleteResponse res = await constructorio.Autocomplete.GetAutocompleteResults(req);

Assert.NotNull(res.ResultId, "Result id exists");
res.Request.TryGetValue("pre_filter_expression", out object reqPreFilterExpression);
Assert.AreEqual(
JObject.Parse(filterByGroupId.GetExpression()),
reqPreFilterExpression,
"Pre Filter Expression is sent in request"
);
}

[Test]
public async Task GetAutocompleteResultsShouldReturnResultWithPreFilterExpressionPerSection()
{
ValuePreFilterExpression filterByGroupId = new ValuePreFilterExpression("group_id", "All");
AutocompleteRequest req = new AutocompleteRequest("item")
{
UserInfo = UserInfo,
PreFilterExpressionPerSection = new List<PreFilterExpressionPerSection>
{
new PreFilterExpressionPerSection("Products", filterByGroupId),
},
};
ConstructorIO constructorio = new ConstructorIO(this.Config);
AutocompleteResponse res = await constructorio.Autocomplete.GetAutocompleteResults(req);

Assert.NotNull(res.ResultId, "Result id exists");
res.Request.TryGetValue("pre_filter_expression", out object reqPreFilterExpression);
JObject parsedPreFilterExpression = (JObject)reqPreFilterExpression;
Assert.NotNull(parsedPreFilterExpression, "Pre filter expression exists in response");
Assert.AreEqual(
JObject.Parse(filterByGroupId.GetExpression()),
parsedPreFilterExpression["Products"],
"Per-section pre filter expression is sent in request"
);
}

[Test]
public async Task GetAutocompleteResultsShouldReturnResultWithMultiplePreFilterExpressionsPerSection()
{
ValuePreFilterExpression filterByGroupId = new ValuePreFilterExpression("group_id", "All");
AndPreFilterExpression filterByPriceAndBrand = new AndPreFilterExpression(
new List<PreFilterExpression>
{
new RangePreFilterExpression("price", new List<string> { "10", "100" }),
new ValuePreFilterExpression("brand", "Nike"),
}
);
AutocompleteRequest req = new AutocompleteRequest("item")
{
UserInfo = UserInfo,
PreFilterExpressionPerSection = new List<PreFilterExpressionPerSection>
{
new PreFilterExpressionPerSection("Products", filterByGroupId),
new PreFilterExpressionPerSection("Search Suggestions", filterByPriceAndBrand),
},
};
ConstructorIO constructorio = new ConstructorIO(this.Config);
AutocompleteResponse res = await constructorio.Autocomplete.GetAutocompleteResults(req);

Assert.NotNull(res.ResultId, "Result id exists");
res.Request.TryGetValue("pre_filter_expression", out object reqPreFilterExpression);
JObject parsedPreFilterExpression = (JObject)reqPreFilterExpression;
Assert.NotNull(parsedPreFilterExpression, "Pre filter expression exists in response");
Assert.AreEqual(
JObject.Parse(filterByGroupId.GetExpression()),
parsedPreFilterExpression["Products"],
"Value per-section pre filter expression is sent in request"
);
Assert.AreEqual(
JObject.Parse(filterByPriceAndBrand.GetExpression()),
parsedPreFilterExpression["Search Suggestions"],
"Composite per-section pre filter expression is sent in request"
);
}

[Test]
public async Task GetAutocompleteResultsShouldReturnResultWithFiltersPerSection()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,53 @@ public void GetRequestParameters()
Assert.AreEqual(this.FiltersPerSection, requestParameters[Constants.FILTERS_PER_SECTION]);
}

[Test]
public void GetRequestParametersWithPreFilterExpression()
{
ValuePreFilterExpression filterByBrand = new ValuePreFilterExpression("Brand", "XYZ");
AutocompleteRequest req = new AutocompleteRequest(this.Query)
{
PreFilterExpression = filterByBrand,
};

Hashtable requestParameters = req.GetRequestParameters();
Assert.IsNotNull(requestParameters[Constants.PRE_FILTER_EXPRESSION]);
Assert.IsTrue(requestParameters[Constants.PRE_FILTER_EXPRESSION].ToString().Contains("Brand"));
Assert.IsTrue(requestParameters[Constants.PRE_FILTER_EXPRESSION].ToString().Contains("XYZ"));
}

[Test]
public void GetRequestParametersWithPreFilterExpressionPerSection()
{
ValuePreFilterExpression filterProducts = new ValuePreFilterExpression("Brand", "XYZ");
ValuePreFilterExpression filterSuggestions = new ValuePreFilterExpression("group_id", "All");
AutocompleteRequest req = new AutocompleteRequest(this.Query)
{
PreFilterExpressionPerSection = new List<PreFilterExpressionPerSection>
{
new PreFilterExpressionPerSection("Products", filterProducts),
new PreFilterExpressionPerSection("Search Suggestions", filterSuggestions),
},
};

Hashtable requestParameters = req.GetRequestParameters();
List<PreFilterExpressionPerSection> perSection = (List<PreFilterExpressionPerSection>)requestParameters[Constants.PRE_FILTER_EXPRESSION_PER_SECTION];
Assert.IsNotNull(perSection);
Assert.AreEqual(2, perSection.Count);
Assert.AreEqual("Products", perSection[0].Section);
Assert.AreEqual("Search Suggestions", perSection[1].Section);
}

[Test]
public void GetRequestParametersWithoutPreFilterExpression()
{
AutocompleteRequest req = new AutocompleteRequest(this.Query);

Hashtable requestParameters = req.GetRequestParameters();
Assert.IsFalse(requestParameters.ContainsKey(Constants.PRE_FILTER_EXPRESSION));
Assert.IsFalse(requestParameters.ContainsKey(Constants.PRE_FILTER_EXPRESSION_PER_SECTION));
}

[Test]
public void GetRequestHeaders()
{
Expand Down
22 changes: 22 additions & 0 deletions src/Constructorio_NET.Tests/utils/HelpersTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,28 @@ public void MakeUrlSearchWithFiltersPerSection()
Assert.That(hasColorBlueFilter && hasColorGreenFilter, "url is properly formed and has all filters applied");
}

[Test]
public void MakeUrlAutocompleteWithPreFilterExpressionPerSection()
{
List<string> paths = new List<string> { "autocomplete", this.Query };
List<PreFilterExpressionPerSection> preFilterExpressionPerSection = new List<PreFilterExpressionPerSection>
{
new PreFilterExpressionPerSection("Products", new ValuePreFilterExpression("Brand", "XYZ")),
new PreFilterExpressionPerSection("Search Suggestions", new ValuePreFilterExpression("group_id", "All")),
};
Hashtable queryParams = new Hashtable()
{
{ Constants.PRE_FILTER_EXPRESSION_PER_SECTION, preFilterExpressionPerSection },
};

string url = MakeUrl(this.Options, paths, queryParams);
bool hasProductsKey = Regex.Match(url, "&pre_filter_expression%5BProducts%5D=").Success;
bool hasSuggestionsKey = Regex.Match(url, "&pre_filter_expression%5BSearch%20Suggestions%5D=").Success;
bool hasBrandExpression = url.Contains(OurEscapeDataString("XYZ"));
bool hasGroupExpression = url.Contains(OurEscapeDataString("All"));
Assert.That(hasProductsKey && hasSuggestionsKey && hasBrandExpression && hasGroupExpression, "url should have bracketed per-section pre_filter_expression");
}

[Test]
public async Task TestCreateRequest()
{
Expand Down
21 changes: 21 additions & 0 deletions src/constructor.io/models/Autocomplete/AutocompleteRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ public class AutocompleteRequest : IFilterable, IUserDetails
/// </summary>
public Dictionary<string, Dictionary<string, List<string>>> FiltersPerSection { get; set; }

/// <summary>
/// Gets or sets the filter expression used to scope results across all sections.
/// </summary>
public PreFilterExpression PreFilterExpression { get; set; }

/// <summary>
/// Gets or sets per-section filter expressions used to scope results for specific sections.
/// Serialized as pre_filter_expression[Section]={...}.
/// </summary>
public List<PreFilterExpressionPerSection> PreFilterExpressionPerSection { get; set; }

/// <summary>
/// Gets or sets the format options used to refine result groups.
/// </summary>
Expand Down Expand Up @@ -105,6 +116,16 @@ public Hashtable GetRequestParameters()
parameters.Add(Constants.FILTERS_PER_SECTION, this.FiltersPerSection);
}

if (this.PreFilterExpression != null)
{
parameters.Add(Constants.PRE_FILTER_EXPRESSION, this.PreFilterExpression.GetExpression());
}

if (this.PreFilterExpressionPerSection != null && this.PreFilterExpressionPerSection.Count > 0)
{
parameters.Add(Constants.PRE_FILTER_EXPRESSION_PER_SECTION, this.PreFilterExpressionPerSection);
}

if (this.TestCells != null)
{
parameters.Add(Constants.TEST_CELLS, this.TestCells);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace Constructorio_NET.Models
{
/// <summary>
/// Associates a <see cref="PreFilterExpression"/> with a specific autocomplete section.
/// Serialized to the documented bracket-notation shape (e.g. pre_filter_expression[Products]={...}).
/// </summary>
public class PreFilterExpressionPerSection
{
/// <summary>
/// Gets or sets the section the expression applies to (e.g. "Products", "Search Suggestions").
/// </summary>
public string Section { get; set; }

/// <summary>
/// Gets or sets the pre-filter expression to scope results for the section.
/// </summary>
public PreFilterExpression Expression { get; set; }

/// <summary>
/// Initializes a new instance of the <see cref="PreFilterExpressionPerSection"/> class.
/// </summary>
/// <param name="section">Section the expression applies to.</param>
/// <param name="expression">Pre-filter expression for the section.</param>
public PreFilterExpressionPerSection(string section, PreFilterExpression expression)
{
this.Section = section;
this.Expression = expression;
}

/// <summary>
/// Initializes a new instance of the <see cref="PreFilterExpressionPerSection"/> class.
/// </summary>
public PreFilterExpressionPerSection()
{
}
}
}
1 change: 1 addition & 0 deletions src/constructor.io/utils/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public static class Constants
public const string QUIZ_VERSION_ID = "quiz_version_id";
public const string QUIZ_SESSION_ID = "quiz_session_id";
public const string PRE_FILTER_EXPRESSION = "pre_filter_expression";
public const string PRE_FILTER_EXPRESSION_PER_SECTION = "pre_filter_expression_per_section";
public const string QS_PARAM = "qs";
public const string ON_MISSING = "on_missing";
public const string FORMAT = "format";
Expand Down
19 changes: 19 additions & 0 deletions src/constructor.io/utils/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,25 @@ protected static string MakeUrl(Hashtable options, List<string> paths, Hashtable
}
}

if (queryParams.Contains(Constants.PRE_FILTER_EXPRESSION_PER_SECTION))
{
List<PreFilterExpressionPerSection> preFilterExpressionPerSection = (List<PreFilterExpressionPerSection>)queryParams[Constants.PRE_FILTER_EXPRESSION_PER_SECTION];
queryParams.Remove(Constants.PRE_FILTER_EXPRESSION_PER_SECTION);

foreach (var sectionExpression in preFilterExpressionPerSection)
{
if (sectionExpression?.Section == null || sectionExpression.Expression == null)
{
continue;
}

url.Append("&" + Constants.PRE_FILTER_EXPRESSION + UrlEscapedStartSquareBracket)
.Append(OurEscapeDataString(sectionExpression.Section))
.Append(UrlEscapedEndSquareBracket + "=")
.Append(OurEscapeDataString(sectionExpression.Expression.GetExpression()));
}
}

// Add test cells to query string
if (queryParams.Contains(Constants.TEST_CELLS))
{
Expand Down
Loading