Skip to content

Commit

Permalink
feat: add order aggregations
Browse files Browse the repository at this point in the history
  • Loading branch information
ksavosteev committed Jan 23, 2024
1 parent e9fd34a commit 73c91ea
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 29 deletions.
1 change: 0 additions & 1 deletion .nuke

This file was deleted.

4 changes: 4 additions & 0 deletions .nuke/parameters.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "./build.schema.json",
"Solution": "VirtoCommerce.OrdersModule.sln"
}
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Project>
<!-- These properties will be shared for all projects -->
<PropertyGroup>
<VersionPrefix>3.803.0</VersionPrefix>
<VersionPrefix>3.803.4</VersionPrefix>
<VersionSuffix>
</VersionSuffix>
<VersionSuffix Condition=" '$(VersionSuffix)' != '' AND '$(BuildNumber)' != '' ">$(VersionSuffix)-$(BuildNumber)</VersionSuffix>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,69 @@
using System;
using VirtoCommerce.Platform.Core.Common;
using System.Collections.Generic;

namespace VirtoCommerce.OrdersModule.Core.Model.Search
{
[Obsolete("Use CustomerOrderSearchCriteria", DiagnosticId = "VC0008", UrlFormat = "https://docs.virtocommerce.org/products/products-virto3-versions/")]
public class CustomerOrderIndexedSearchCriteria : SearchCriteriaBase
public class CustomerOrderIndexedSearchCriteria : CustomerOrderSearchCriteria
{
public string Facet { get; set; }
}

public class CustomerOrderIndexedSearchResult : CustomerOrderSearchResult
{
public virtual IList<OrderAggregation> Aggregations { get; set; }
}

public class OrderAggregation
{
/// <summary>
/// Gets or sets the value of the aggregation type
/// </summary>
/// <value>
/// "Attribute", "Range"
/// </value>
public string AggregationType { get; set; }

/// <summary>
/// Gets or sets the value of the aggregation field
/// </summary>
public string Field { get; set; }

/// <summary>
/// Gets or sets the collection of the aggregation labels
/// </summary>
public IList<OrderAggregationLabel> Labels { get; set; }

/// <summary>
/// Gets or sets the collection of the aggregation items
/// </summary>
public IList<OrderAggregationItem> Items { get; set; }
}

public class OrderAggregationLabel
{
public string Language { get; set; }
public string Label { get; set; }
}

public class OrderAggregationItem
{
/// <summary>
/// Gets or sets the aggregation item value
/// </summary>
public object Value { get; set; }

/// <summary>
/// Gets or sets the aggregation item count
/// </summary>
public int Count { get; set; }

/// <summary>
/// Gets or sets the flag for aggregation item is applied
/// </summary>
public bool IsApplied { get; set; }

/// <summary>
/// Gets or sets the collection of the aggregation item labels
/// </summary>
public IList<OrderAggregationLabel> Labels { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ namespace VirtoCommerce.OrdersModule.Core.Search.Indexed
{
public interface IIndexedCustomerOrderSearchService
{
Task<CustomerOrderSearchResult> SearchCustomerOrdersAsync(CustomerOrderSearchCriteria criteria);
Task<CustomerOrderIndexedSearchResult> SearchCustomerOrdersAsync(CustomerOrderIndexedSearchCriteria criteria);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using VirtoCommerce.OrdersModule.Core;
Expand All @@ -25,13 +27,16 @@ public Task<SearchRequest> BuildRequestAsync(SearchCriteriaBase criteria)
{
// GetFilters() modifies Keyword
criteria = criteria.CloneTyped();
var filters = GetFilters(criteria);
var filter = GetFilters(criteria).And();
var aggregations = GetAggregations(criteria);
aggregations = ApplyMultiSelectFacetSearch(aggregations, filter);

var request = new SearchRequest
{
SearchKeywords = criteria.Keyword,
SearchFields = new[] { IndexDocumentExtensions.ContentFieldName },
Filter = filters.And(),
Filter = filter,
Aggregations = aggregations,
Sorting = GetSorting(criteria),
Skip = criteria.Skip,
Take = criteria.Take,
Expand All @@ -40,41 +45,57 @@ public Task<SearchRequest> BuildRequestAsync(SearchCriteriaBase criteria)
return Task.FromResult(request);
}

protected virtual IList<IFilter> GetFilters(SearchCriteriaBase criteria)
private IList<AggregationRequest> GetAggregations(SearchCriteriaBase criteria)
{
var result = new List<IFilter>();
var result = new List<AggregationRequest>();

if (criteria.ObjectIds?.Any() == true)
if (criteria is not CustomerOrderIndexedSearchCriteria indexedSearchCriteria || string.IsNullOrEmpty(indexedSearchCriteria.Facet))
{
result.Add(new IdsFilter { Values = criteria.ObjectIds });
return result;
}

if (criteria is CustomerOrderSearchCriteria orderSearchCriteria)
{
result.AddRange(GetPermanentFilters(orderSearchCriteria));
}
var facetExpessions = indexedSearchCriteria.Facet.Split(" ", StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
result = facetExpessions
.Select(x => new TermAggregationRequest
{
FieldName = x,
Id = x,
Size = 0
})
.Cast<AggregationRequest>()
.ToList();

return result;
}



protected virtual IList<IFilter> GetPermanentFilters(CustomerOrderSearchCriteria criteria)
protected virtual IList<IFilter> GetFilters(SearchCriteriaBase criteria)
{
var result = new List<IFilter>();

if (criteria.ObjectIds?.Any() == true)
{
result.Add(new IdsFilter { Values = criteria.ObjectIds });
}

if (!string.IsNullOrEmpty(criteria.Keyword))
{
var parseResult = _searchPhraseParser.Parse(criteria.Keyword);
criteria.Keyword = parseResult.Keyword;
result.AddRange(parseResult.Filters);
}

if (criteria.ObjectIds != null)
if (criteria is CustomerOrderSearchCriteria orderSearchCriteria)
{
result.Add(new IdsFilter { Values = criteria.ObjectIds });
result.AddRange(GetPermanentFilters(orderSearchCriteria));
}

return result;
}

protected virtual IList<IFilter> GetPermanentFilters(CustomerOrderSearchCriteria criteria)
{
var result = new List<IFilter>();

if (!criteria.StoreIds.IsNullOrEmpty())
{
result.Add(FilterHelper.CreateTermFilter("storeid", criteria.StoreIds));
Expand Down Expand Up @@ -113,7 +134,6 @@ protected virtual IList<IFilter> GetPermanentFilters(CustomerOrderSearchCriteria
result.Add(FilterHelper.CreateTermFilter("isprototype", "false"));
}


return result;
}

Expand All @@ -131,5 +151,45 @@ protected virtual IList<SortingField> GetSorting(SearchCriteriaBase criteria)

return result;
}

public static IList<AggregationRequest> ApplyMultiSelectFacetSearch(IList<AggregationRequest> aggregations, IFilter filter)
{
foreach (var aggregation in aggregations ?? Array.Empty<AggregationRequest>())
{
var aggregationFilterFieldName = aggregation.FieldName ?? (aggregation.Filter as INamedFilter)?.FieldName;

IList<IFilter> childFilters;
var clonedFilter = (IFilter)filter.Clone();
if (clonedFilter is AndFilter andFilter)
{
childFilters = andFilter.ChildFilters;
}
else
{
childFilters = new List<IFilter>() { clonedFilter };
}

// For multi-select facet mechanism, we should select
// search request filters which do not have the same
// names such as aggregation filter
childFilters = childFilters
.Where(x =>
{
var result = true;

if (x is INamedFilter namedFilter)
{
result = !(aggregationFilterFieldName?.StartsWith(namedFilter.FieldName, true, CultureInfo.InvariantCulture) ?? false);
}

return result;
})
.ToList();

aggregation.Filter = aggregation.Filter == null ? clonedFilter : aggregation.Filter.And(clonedFilter);
}

return aggregations;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public IndexedCustomerOrderSearchService(ISearchRequestBuilderRegistrar searchRe
_configuration = configuration;
}

public virtual async Task<CustomerOrderSearchResult> SearchCustomerOrdersAsync(CustomerOrderSearchCriteria criteria)
public virtual async Task<CustomerOrderIndexedSearchResult> SearchCustomerOrdersAsync(CustomerOrderIndexedSearchCriteria criteria)
{
if (!_configuration.IsOrderFullTextSearchEnabled())
{
Expand All @@ -42,24 +42,25 @@ public virtual async Task<CustomerOrderSearchResult> SearchCustomerOrdersAsync(C

var response = await _searchProvider.SearchAsync(ModuleConstants.OrderIndexDocumentType, request);

var result = await ConvertResponseAsync(response, criteria);
var result = await ConvertResponseAsync(response, criteria, request);
return result;
}

protected virtual async Task<CustomerOrderSearchResult> ConvertResponseAsync(SearchResponse response, CustomerOrderSearchCriteria criteria)
protected virtual async Task<CustomerOrderIndexedSearchResult> ConvertResponseAsync(SearchResponse response, CustomerOrderIndexedSearchCriteria criteria, SearchRequest searchRequest)
{
var result = AbstractTypeFactory<CustomerOrderSearchResult>.TryCreateInstance();
var result = AbstractTypeFactory<CustomerOrderIndexedSearchResult>.TryCreateInstance();

if (response != null)
{
result.TotalCount = (int)response.TotalCount;
result.Results = await ConvertDocumentsAsync(response.Documents, criteria);
result.Aggregations = ConvertAggregations(response.Aggregations, searchRequest);
}

return result;
}

protected virtual async Task<IList<CustomerOrder>> ConvertDocumentsAsync(IList<SearchDocument> documents, CustomerOrderSearchCriteria criteria)
protected virtual async Task<IList<CustomerOrder>> ConvertDocumentsAsync(IList<SearchDocument> documents, CustomerOrderIndexedSearchCriteria criteria)
{
var result = new List<CustomerOrder>();

Expand All @@ -82,5 +83,43 @@ protected virtual async Task<IList<CustomerOrder>> ConvertDocumentsAsync(IList<S

return result;
}

private static IList<OrderAggregation> ConvertAggregations(IList<AggregationResponse> aggregationResponses, SearchRequest searchRequest)
{
var result = new List<OrderAggregation>();

foreach (var aggregationRequest in searchRequest.Aggregations)
{
var aggregationResponse = aggregationResponses.FirstOrDefault(x => x.Id == aggregationRequest.Id);
if (aggregationResponse != null)
{
var orderAggregation = new OrderAggregation()
{
Field = aggregationRequest.FieldName,
Items = GetAttributeAggregationItems(aggregationResponse.Values).ToArray(),
};

result.Add(orderAggregation);
}
}

return result;
}

private static IList<OrderAggregationItem> GetAttributeAggregationItems(IList<AggregationResponseValue> aggregationResponseValues)
{
var result = aggregationResponseValues
.Select(v =>
{
return new OrderAggregationItem
{
Value = v.Id,
Count = (int)v.Count
};
})
.ToList();

return result;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ public ActionResult GetOrderFullTextSearchEnabled()

[HttpPost]
[Route("indexed/search")]
public async Task<ActionResult<CustomerOrderSearchResult>> SearchCustomerOrderIndexed([FromBody] CustomerOrderSearchCriteria criteria)
public async Task<ActionResult<CustomerOrderSearchResult>> SearchCustomerOrderIndexed([FromBody] CustomerOrderIndexedSearchCriteria criteria)
{
var result = await _indexedSearchService.SearchCustomerOrdersAsync(criteria);
return Content(JsonConvert.SerializeObject(result, _outputJsonSerializerSettings), "application/json");
Expand Down

0 comments on commit 73c91ea

Please sign in to comment.