public IHttpActionResult Search(string store, string[] priceLists, [ModelBinder(typeof(SearchParametersBinder))] SearchParameters parameters, [FromUri] coreModel.ItemResponseGroup responseGroup = coreModel.ItemResponseGroup.ItemMedium, [FromUri] string outline = "", string language = "en-us", string currency = "USD") { var context = new Dictionary<string, object> { { "StoreId", store }, }; var fullLoadedStore = GetStoreById(store); if (fullLoadedStore == null) { throw new NullReferenceException(store + " not found"); } var catalog = fullLoadedStore.Catalog; string categoryId = null; var criteria = new CatalogIndexedSearchCriteria { Locale = language, Catalog = catalog.ToLowerInvariant() }; if (!string.IsNullOrWhiteSpace(outline)) { criteria.Outlines.Add(String.Format("{0}/{1}*", catalog, outline)); categoryId = outline.Split(new[] { '/' }).Last(); context.Add("CategoryId", categoryId); } #region Filters // Now fill in filters var filters = _browseFilterService.GetFilters(context); // Add all filters foreach (var filter in filters) { criteria.Add(filter); } // apply terms if (parameters.Terms != null && parameters.Terms.Count > 0) { foreach (var term in parameters.Terms) { var filter = filters.SingleOrDefault(x => x.Key.Equals(term.Key, StringComparison.OrdinalIgnoreCase) && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(currency, StringComparison.OrdinalIgnoreCase))); var appliedFilter = _browseFilterService.Convert(filter, term.Value); criteria.Apply(appliedFilter); } } #endregion #region Facets // apply facet filters var facets = parameters.Facets; if (facets.Count != 0) { foreach (var key in facets.Keys) { var filter = filters.SingleOrDefault( x => x.Key.Equals(key, StringComparison.OrdinalIgnoreCase) && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(currency, StringComparison.OrdinalIgnoreCase))); var appliedFilter = _browseFilterService.Convert(filter, facets[key]); criteria.Apply(appliedFilter); } } #endregion //criteria.ClassTypes.Add("Product"); criteria.RecordsToRetrieve = parameters.PageSize == 0 ? 10 : parameters.PageSize; criteria.StartingRecord = parameters.StartingRecord; criteria.Pricelists = priceLists; criteria.Currency = currency; criteria.StartDateFrom = parameters.StartDateFrom; criteria.SearchPhrase = parameters.FreeSearch; #region sorting if (!string.IsNullOrEmpty(parameters.Sort)) { var isDescending = "desc".Equals(parameters.SortOrder, StringComparison.OrdinalIgnoreCase); SearchSort sortObject = null; switch (parameters.Sort.ToLowerInvariant()) { case "price": if (criteria.Pricelists != null) { sortObject = new SearchSort( criteria.Pricelists.Select( priceList => new SearchSortField(String.Format("price_{0}_{1}", criteria.Currency.ToLower(), priceList.ToLower())) { IgnoredUnmapped = true, IsDescending = isDescending, DataType = SearchSortField.DOUBLE }) .ToArray()); } break; case "position": sortObject = new SearchSort( new SearchSortField(string.Format("sort{0}{1}", catalog, categoryId).ToLower()) { IgnoredUnmapped = true, IsDescending = isDescending }); break; case "name": sortObject = new SearchSort("name", isDescending); break; case "rating": sortObject = new SearchSort(criteria.ReviewsAverageField, isDescending); break; case "reviews": sortObject = new SearchSort(criteria.ReviewsTotalField, isDescending); break; default: sortObject = CatalogIndexedSearchCriteria.DefaultSortOrder; break; } criteria.Sort = sortObject; } #endregion //Load ALL products var searchResults = _browseService.SearchItems(criteria, responseGroup); // populate inventory if ((responseGroup & ItemResponseGroup.ItemProperties) == ItemResponseGroup.ItemProperties) { PopulateInventory(fullLoadedStore.FulfillmentCenter, searchResults.Items); } return this.Ok(searchResults); }
private SearchResult SearchProducts(SearchCriteria criteria) { var context = new Dictionary<string, object> { { "StoreId", criteria.StoreId }, }; var store = _storeService.GetById(criteria.StoreId); if (store == null) { throw new NullReferenceException("Cannot find store '" + criteria.StoreId + "'"); } var catalog = store.Catalog; var categoryId = criteria.CategoryId; var serviceCriteria = new CatalogIndexedSearchCriteria { Locale = criteria.LanguageCode, Catalog = catalog.ToLowerInvariant(), IsFuzzySearch = true, }; if (!string.IsNullOrWhiteSpace(criteria.Outline)) { serviceCriteria.Outlines.Add(string.Format(CultureInfo.InvariantCulture, "{0}/{1}*", catalog, criteria.Outline)); categoryId = criteria.Outline.Split('/').Last(); } else { if (!string.IsNullOrEmpty(categoryId)) { serviceCriteria.Outlines.Add(string.Format(CultureInfo.InvariantCulture, "{0}/{1}*", catalog, categoryId)); } } if (!string.IsNullOrEmpty(categoryId)) { context.Add("CategoryId", categoryId); } #region Filters // Now fill in filters var filters = _browseFilterService.GetFilters(context); // Add all filters foreach (var filter in filters) { serviceCriteria.Add(filter); } // apply terms var terms = ParseKeyValues(criteria.Terms); if (terms.Any()) { var filtersWithValues = filters .Where(x => (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(criteria.Currency, StringComparison.OrdinalIgnoreCase))) .Select(x => new { Filter = x, Values = x.GetValues() }) .ToList(); foreach (var term in terms) { var filter = filters.SingleOrDefault(x => x.Key.Equals(term.Key, StringComparison.OrdinalIgnoreCase) && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(criteria.Currency, StringComparison.OrdinalIgnoreCase))); // handle special filter term with a key = "tags", it contains just values and we need to determine which filter to use if (filter == null && term.Key == "tags") { foreach (var termValue in term.Values) { // try to find filter by value var foundFilter = filtersWithValues.FirstOrDefault(x => x.Values.Any(y => y.Id.Equals(termValue))); if (foundFilter != null) { filter = foundFilter.Filter; var appliedFilter = _browseFilterService.Convert(filter, term.Values); serviceCriteria.Apply(appliedFilter); } } } else { var appliedFilter = _browseFilterService.Convert(filter, term.Values); serviceCriteria.Apply(appliedFilter); } } } #endregion #region Facets // apply facet filters var facets = ParseKeyValues(criteria.Facets); foreach (var facet in facets) { var filter = filters.SingleOrDefault( x => x.Key.Equals(facet.Key, StringComparison.OrdinalIgnoreCase) && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(criteria.Currency, StringComparison.OrdinalIgnoreCase))); var appliedFilter = _browseFilterService.Convert(filter, facet.Values); serviceCriteria.Apply(appliedFilter); } #endregion //criteria.ClassTypes.Add("Product"); serviceCriteria.RecordsToRetrieve = criteria.Take <= 0 ? 10 : criteria.Take; serviceCriteria.StartingRecord = criteria.Skip; serviceCriteria.Pricelists = criteria.PricelistIds; serviceCriteria.Currency = criteria.Currency; serviceCriteria.StartDateFrom = criteria.StartDateFrom; serviceCriteria.SearchPhrase = criteria.Keyword; #region sorting if (!string.IsNullOrEmpty(criteria.Sort)) { var isDescending = "desc".Equals(criteria.SortOrder, StringComparison.OrdinalIgnoreCase); SearchSort sortObject = null; switch (criteria.Sort.ToLowerInvariant()) { case "price": if (serviceCriteria.Pricelists != null) { sortObject = new SearchSort( serviceCriteria.Pricelists.Select( priceList => new SearchSortField(String.Format("price_{0}_{1}", serviceCriteria.Currency.ToLower(), priceList.ToLower())) { IgnoredUnmapped = true, IsDescending = isDescending, DataType = SearchSortField.DOUBLE }) .ToArray()); } break; case "position": sortObject = new SearchSort( new SearchSortField(string.Concat("sort", catalog, categoryId).ToLower()) { IgnoredUnmapped = true, IsDescending = isDescending }); break; case "name": sortObject = new SearchSort("name", isDescending); break; case "rating": sortObject = new SearchSort(serviceCriteria.ReviewsAverageField, isDescending); break; case "reviews": sortObject = new SearchSort(serviceCriteria.ReviewsTotalField, isDescending); break; default: sortObject = CatalogIndexedSearchCriteria.DefaultSortOrder; break; } serviceCriteria.Sort = sortObject; } #endregion var responseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.ItemAssets | ItemResponseGroup.Seo; if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties) { responseGroup |= ItemResponseGroup.ItemProperties; } if ((criteria.ResponseGroup & SearchResponseGroup.WithVariations) == SearchResponseGroup.WithVariations) { responseGroup |= ItemResponseGroup.Variations; } //Load ALL products var searchResults = _browseService.SearchItems(serviceCriteria, responseGroup); // populate inventory //if ((request.ResponseGroup & ItemResponseGroup.ItemProperties) == ItemResponseGroup.ItemProperties) if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties) { PopulateInventory(store.FulfillmentCenter, searchResults.Products); } return searchResults; }
public IHttpActionResult Search([FromUri] ProductSearchRequest request) { request = request ?? new ProductSearchRequest(); request.Normalize(); var context = new Dictionary<string, object> { { "StoreId", request.Store }, }; var fullLoadedStore = GetStoreById(request.Store); if (fullLoadedStore == null) { throw new NullReferenceException(request.Store + " not found"); } var catalog = fullLoadedStore.Catalog; string categoryId = null; var criteria = new CatalogIndexedSearchCriteria { Locale = request.Language, Catalog = catalog.ToLowerInvariant(), IsFuzzySearch = true }; if (!string.IsNullOrWhiteSpace(request.Outline)) { criteria.Outlines.Add(string.Format("{0}/{1}*", catalog, request.Outline)); categoryId = request.Outline.Split(new[] { '/' }).Last(); context.Add("CategoryId", categoryId); } #region Filters // Now fill in filters var filters = _browseFilterService.GetFilters(context); // Add all filters foreach (var filter in filters) { criteria.Add(filter); } // apply terms var terms = ParseKeyValues(request.Terms); if (terms.Any()) { var filtersWithValues = filters .Where(x => (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(request.Currency, StringComparison.OrdinalIgnoreCase))) .Select(x => new { Filter = x, Values = x.GetValues() }) .ToList(); foreach (var term in terms) { var filter = filters.SingleOrDefault(x => x.Key.Equals(term.Key, StringComparison.OrdinalIgnoreCase) && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(request.Currency, StringComparison.OrdinalIgnoreCase))); // handle special filter term with a key = "tags", it contains just values and we need to determine which filter to use if (filter == null && term.Key == "tags") { foreach (var termValue in term.Values) { // try to find filter by value var foundFilter = filtersWithValues.FirstOrDefault(x => x.Values.Any(y => y.Id.Equals(termValue))); if (foundFilter != null) { filter = foundFilter.Filter; var appliedFilter = _browseFilterService.Convert(filter, term.Values); criteria.Apply(appliedFilter); } } } else { var appliedFilter = _browseFilterService.Convert(filter, term.Values); criteria.Apply(appliedFilter); } } } #endregion #region Facets // apply facet filters var facets = ParseKeyValues(request.Facets); foreach (var facet in facets) { var filter = filters.SingleOrDefault( x => x.Key.Equals(facet.Key, StringComparison.OrdinalIgnoreCase) && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(request.Currency, StringComparison.OrdinalIgnoreCase))); var appliedFilter = _browseFilterService.Convert(filter, facet.Values); criteria.Apply(appliedFilter); } #endregion //criteria.ClassTypes.Add("Product"); criteria.RecordsToRetrieve = request.Take <= 0 ? 10 : request.Take; criteria.StartingRecord = request.Skip; criteria.Pricelists = request.Pricelists; criteria.Currency = request.Currency; criteria.StartDateFrom = request.StartDateFrom; criteria.SearchPhrase = request.SearchPhrase; #region sorting if (!string.IsNullOrEmpty(request.Sort)) { var isDescending = "desc".Equals(request.SortOrder, StringComparison.OrdinalIgnoreCase); SearchSort sortObject = null; switch (request.Sort.ToLowerInvariant()) { case "price": if (criteria.Pricelists != null) { sortObject = new SearchSort( criteria.Pricelists.Select( priceList => new SearchSortField(String.Format("price_{0}_{1}", criteria.Currency.ToLower(), priceList.ToLower())) { IgnoredUnmapped = true, IsDescending = isDescending, DataType = SearchSortField.DOUBLE }) .ToArray()); } break; case "position": sortObject = new SearchSort( new SearchSortField(string.Format("sort{0}{1}", catalog, categoryId).ToLower()) { IgnoredUnmapped = true, IsDescending = isDescending }); break; case "name": sortObject = new SearchSort("name", isDescending); break; case "rating": sortObject = new SearchSort(criteria.ReviewsAverageField, isDescending); break; case "reviews": sortObject = new SearchSort(criteria.ReviewsTotalField, isDescending); break; default: sortObject = CatalogIndexedSearchCriteria.DefaultSortOrder; break; } criteria.Sort = sortObject; } #endregion //Load ALL products var searchResults = _browseService.SearchItems(criteria, request.ResponseGroup); // populate inventory if ((request.ResponseGroup & ItemResponseGroup.ItemProperties) == ItemResponseGroup.ItemProperties) { PopulateInventory(fullLoadedStore.FulfillmentCenter, searchResults.Items); } return Ok(searchResults); }
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { if (bindingContext.ModelType != typeof(CatalogIndexedSearchCriteria)) { return false; } var key = actionContext.Request.RequestUri.Query; var qs = HttpUtility.ParseQueryString(key); var qsDict = this.NvToDict(qs); // parse facets var facets = qsDict.Where(k => FacetRegex.IsMatch(k.Key)) .Select(k => k.WithKey(FacetRegex.Replace(k.Key, ""))) .ToDictionary(x => x.Key, y => y.Value.Split(',')); // parse facets var terms = qsDict.Where(k => TermRegex.IsMatch(k.Key)) .Select(k => k.WithKey(TermRegex.Replace(k.Key, ""))) .ToDictionary(x => x.Key, y => y.Value.Split(',')); var result = new CatalogIndexedSearchCriteria { SearchPhrase = qs["q"].EmptyToNull(), RecordsToRetrieve = qs["take"].TryParse(20), StartingRecord = qs["skip"].TryParse(0), }; // apply filters if one specified if (terms.Count > 0) { foreach (var term in terms) { var termFilter = new AttributeFilter { Key = term.Key.ToLowerInvariant(), Values = term.Value.Select( x => new AttributeFilterValue() { Id = x.ToLowerInvariant(), Value = x.ToLowerInvariant() }).ToArray() }; result.Apply(termFilter); } } //result.ClassTypes.Add("Product"); var startDateFromStr = qs["startdatefrom"].EmptyToNull(); if (!string.IsNullOrWhiteSpace(startDateFromStr)) { DateTime startDateFrom; if (DateTime.TryParse(startDateFromStr, out startDateFrom)) { result.StartDateFrom = startDateFrom; } } //TODO load pricelists result.Pricelists = null; result.Currency = qs["curreny"].EmptyToNull(); var sortQuery = qs["sort"].EmptyToNull(); var sort = string.IsNullOrEmpty(sortQuery) ? "name" : sortQuery; var sortOrder = qs["sortorder"].EmptyToNull(); var outline = qs["outline"].EmptyToNull(); var isDescending = "desc".Equals(sortOrder, StringComparison.OrdinalIgnoreCase); var catalogId = actionContext.ActionArguments.ContainsKey("catalog") ? actionContext.ActionArguments["catalog"] : null; string categoryId = null; if (!string.IsNullOrWhiteSpace(outline)) { categoryId = outline.Split(new[] { '/' }).Last(); } SearchSort sortObject = null; switch (sort.ToLowerInvariant()) { case "price": if (result.Pricelists != null) { sortObject = new SearchSort( result.Pricelists.Select( priceList => new SearchSortField( String.Format( "price_{0}_{1}", result.Currency.ToLower(), priceList.ToLower())) { IgnoredUnmapped = true, IsDescending = isDescending, DataType = SearchSortField.DOUBLE }) .ToArray()); } break; case "position": sortObject = new SearchSort( new SearchSortField(string.Format("sort{0}{1}", catalogId, categoryId).ToLower()) { IgnoredUnmapped = true, IsDescending = isDescending }); break; case "name": sortObject = new SearchSort("name", isDescending); break; case "rating": sortObject = new SearchSort(result.ReviewsAverageField, isDescending); break; case "reviews": sortObject = new SearchSort(result.ReviewsTotalField, isDescending); break; default: sortObject = CatalogIndexedSearchCriteria.DefaultSortOrder; break; } result.Sort = sortObject; //Use fuzzy search to allow spelling error tolerance result.IsFuzzySearch = true; bindingContext.Model = result; return true; }