Ejemplo n.º 1
0
        /// <summary>
        /// Performs a search using the specified <paramref name="options"/>.
        /// </summary>
        /// <param name="operation">The boolean operation the search should be based on.</param>
        /// <param name="options">The options specyfing how the results should be sorted.</param>
        /// <param name="results">The results of the search.</param>
        /// <param name="total">The total amount of results returned by the search.</param>
        protected virtual void Execute(IBooleanOperation operation, ISearchOptions options, out IEnumerable <ISearchResult> results, out long total)
        {
            // Cast the boolean operation to IQueryExecutor
            IQueryExecutor executor = operation;

            // Start the search in Examine
            ISearchResults allResults = executor.Execute(int.MaxValue);

            // Update the total amount of results
            total = allResults.TotalItemCount;

            results = allResults;

            // If "options" implements the interface, results are sorted using the "Sort" method
            if (options is IPostSortOptions postSort)
            {
                results = postSort.Sort(results);
            }

            // If "options" implements implement the interface, the results are paginated
            if (options is IOffsetOptions offset)
            {
                results = results.Skip(offset.Offset).Take(offset.Limit);
            }
        }
Ejemplo n.º 2
0
 public ISearchResult SearchQuery(string indexName, SearchQuery query, ISearchOptions options = default)
 {
     return(SearchQueryAsync(indexName, query, options)
            .ConfigureAwait(false)
            .GetAwaiter()
            .GetResult());
 }
Ejemplo n.º 3
0
        public CurrentP4kFileSystemViewModel(ICurrentP4k currentP4k,
                                             ICurrentItem currentFile,
                                             IPinnedItems selectedItems,
                                             IExtractP4kContent extractP4KContent,
                                             ISearch search,
                                             ISearchOptions searchOptions,
                                             IUiDispatch uiDispatch,
                                             SearchOptionsViewModel searchOptionsViewModel,
                                             IEnumerable <IFileSubStructureProvider> subFileFactories = null)
        {
            _currentP4K        = currentP4k;
            _currentFile       = currentFile;
            _selectedItems     = selectedItems;
            _extractP4KContent = extractP4KContent;
            _search            = search;
            _searchOptions     = searchOptions;
            _uiDispatch        = uiDispatch;
            _subFileFactories  = subFileFactories != null?subFileFactories.ToArray() : new IFileSubStructureProvider[0];

            SearchOptionsViewModel = searchOptionsViewModel;

            Initialize();

            _currentP4K.Changed += Initialize;
        }
Ejemplo n.º 4
0
 public static ISearchResult SearchQuery(this ICluster cluster, string indexName, SearchQuery query,
                                         ISearchOptions options = default)
 {
     return(cluster.SearchQueryAsync(indexName, query, options)
            .ConfigureAwait(false)
            .GetAwaiter()
            .GetResult());
 }
Ejemplo n.º 5
0
 public SearchResultList(ISearchOptions options, IQuery query, long total, IEnumerable <ISearchResult> items)
 {
     Options = options;
     IsDebug = options is IDebugSearchOptions debug && debug.IsDebug;
     Query   = query;
     Total   = total;
     Items   = items;
 }
 protected static void Init()
 {
     _testParam = new TestSearchOptionsParam();
         _jsonSerializer = new DefaultJsonSerializer();
         _searchBiulder = new SearchOptionsBuilder<object>();
         _queryMapper = new FacatedSearchMapper<object>();
         _builder = new TestSearchOptionsParamBuilder(_testParam, _searchBiulder, _queryMapper);
         _searchOptions = new SearchOptions();
 }
Ejemplo n.º 7
0
 protected static void Init()
 {
     _testParam      = new TestSearchOptionsParam();
     _jsonSerializer = new DefaultJsonSerializer();
     _searchBiulder  = new SearchOptionsBuilder <object>();
     _queryMapper    = new FacatedSearchMapper <object>();
     _builder        = new TestSearchOptionsParamBuilder(_testParam, _searchBiulder, _queryMapper);
     _searchOptions  = new SearchOptions();
 }
Ejemplo n.º 8
0
 public QueryOptions(
     ISearchOptions searchOptions,
     IEnumerable <ISortOptions> sortOptions,
     IPaginationOptions paginationOptions)
 {
     SearchOptions     = searchOptions;
     SortOptions       = sortOptions;
     PaginationOptions = paginationOptions;
 }
Ejemplo n.º 9
0
        public SearchOptionsViewModel(ISearchOptions searchOptions,
                                      IKnownFileExtensions knownFileTypes)
        {
            _searchOptions     = searchOptions;
            _knownFileTypes    = knownFileTypes;
            IncludedExtensions = new ObservableCollection <IncludedExtensionViewModel>();
            UpdateKnownFileTypes();

            _knownFileTypes.Changed     += UpdateKnownFileTypes;
            SearchAllSearchableFileTypes = true;
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Performs a search using the specified <paramref name="options"/> and returns the result of that search.
        ///
        /// Each item in the result is parsed to the type of <typeparamref name="TItem"/> using <paramref name="callback"/>.
        /// </summary>
        /// <typeparam name="TItem">The common output type of each item.</typeparam>
        /// <param name="options">The options for the search.</param>
        /// <param name="callback">A callback used for converting an <see cref="ISearchResult"/> to <typeparamref name="TItem"/>.</param>
        /// <returns>An instance of <see cref="SearchResultList{TItem}"/> representing the result of the search.</returns>
        public virtual SearchResultList <TItem> Search <TItem>(ISearchOptions options, Func <ISearchResult, TItem> callback)
        {
            // Make the search in Examine
            SearchResultList results = Search(options);

            // Iterate through and call "callback" for each item
            IEnumerable <TItem> items = results.Items
                                        .Select(callback)
                                        .Where(x => x != null);

            // Wrap the result
            return(new SearchResultList <TItem>(options, results.Query, results.Total, items));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Performs a search using the specified <paramref name="options"/> and returns the result of that search.
        ///
        /// Each item in the result first found in either the content cache or media cache, and then parsed to the type of <typeparamref name="TItem"/> using <paramref name="callback"/>.
        /// </summary>
        /// <typeparam name="TItem">The common output type of each item.</typeparam>
        /// <param name="options">The options for the search.</param>
        /// <param name="callback">A callback used for converting an <see cref="IPublishedContent"/> to <typeparamref name="TItem"/>.</param>
        /// <returns>An instance of <see cref="SearchResultList{TItem}"/> representing the result of the search.</returns>
        public virtual SearchResultList <TItem> Search <TItem>(ISearchOptions options, Func <IPublishedContent, TItem> callback)
        {
            // Make the search in Examine
            SearchResultList results = Search(options);

            // Iterate through the result and look up the content
            IEnumerable <TItem> items = results.Items
                                        .Select(GetPublishedContentFromResult)
                                        .WhereNotNull()
                                        .Select(callback)
                                        .Where(x => x != null);

            // Wrap the result
            return(new SearchResultList <TItem>(options, results.Query, results.Total, items));
        }
        public virtual IEnumerable <SearchResultEntry> GetAncestors(string identity, ISearchOptions searchOptions)
        {
            var ancestors = new List <SearchResultEntry>();

            var parent = this.GetParent(identity, searchOptions);

            while (parent != null)
            {
                ancestors.Add(parent);

                parent = this.GetParent(parent.DistinguishedName, searchOptions);
            }

            return(ancestors.ToArray());
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Performs a search using the specified <paramref name="options"/> and returns the result of that search.
        ///
        /// Each item in the result first found in either the content cache or media cache, and then parsed to the type of <typeparamref name="TItem"/> using <paramref name="callback"/>.
        /// </summary>
        /// <typeparam name="TItem">The common output type of each item.</typeparam>
        /// <param name="options">The options for the search.</param>
        /// <param name="callback">A callback used for converting an <see cref="IPublishedContent"/> to <typeparamref name="TItem"/>.</param>
        /// <returns>An instance of <see cref="SearchResultList{TItem}"/> representing the result of the search.</returns>
        public virtual SearchResultList <TItem> Search <TItem>(ISearchOptions options, Func <IPublishedContent, ISearchResult, TItem> callback)
        {
            // Make the search in Examine
            SearchResultList results = Search(options);

            // Map the search results
            IEnumerable <TItem> items = (
                from x in results.Items
                let content = GetPublishedContentFromResult(x)
                              let result = callback(content, x)
                                           where result != null
                                           select result
                );

            // Wrap the result
            return(new SearchResultList <TItem>(options, results.Query, results.Total, items));
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Performs a search using the specified <paramref name="options"/> and returns the result of that search.
        /// </summary>
        /// <param name="options">The options for the search.</param>
        /// <returns>An instance of <see cref="SearchResultList"/> representing the result of the search.</returns>
        public virtual SearchResultList Search(ISearchOptions options)
        {
            // Start measuring the elapsed time
            Stopwatch sw = Stopwatch.StartNew();

            // Get the searcher from the options
            ISearcher searcher = GetSearcher(options);

            // Create a new Examine query
            IQuery query = CreateQuery(searcher, options);

            // Get the boolean operation via the options class
            IBooleanOperation operation = options.GetBooleanOperation(this, searcher, query);

            // Declare some variables
            long total;
            IEnumerable <ISearchResult> results;

            switch (options)
            {
            case IExecuteOptions execute:
                execute.Execute(operation, out results, out total);
                break;

            case ISortOptions sortOptions:
                Execute(operation, sortOptions, out results, out total);
                break;

            default:
                Execute(operation, options, out results, out total);
                break;
            }

            sw.Stop();

            if (options is IDebugSearchOptions debug && debug.IsDebug)
            {
                _logger.Debug <SearchHelper>("Search of type {Type} completed in {Milliseconds} with {Query}", options.GetType().FullName, sw.ElapsedMilliseconds, query);
            }

            // Wrap the results
            return(new SearchResultList(options, query, total, results));
        }
        public virtual SearchResultEntry GetParent(string identity, ISearchOptions searchOptions)
        {
            var item = this.Get(identity, searchOptions);

            if (item == null)
            {
                return(null);
            }

            var distinguishedName = this.DistinguishedNameParser.Parse(item.DistinguishedName);

            var parentDistinguishedName = distinguishedName.Parent;

            if (parentDistinguishedName == null)
            {
                return(null);
            }

            return(this.Get(parentDistinguishedName.ToString(), searchOptions));
        }
        public SearchResults <T> GetSearchResults <T>(ISearchOptions <T> options) where T : SearchResultItem
        {
            using (var context = _index.GetSearchContext())
            {
                var results = context.GetQueryable <T>(new CultureExecutionContext(options.CultureInfo));

                // filter
                if (options.Filter != null)
                {
                    results = results.Filter(options.Filter);
                }

                // query
                if (options.Predicate != null)
                {
                    results = results.Where(options.Predicate);
                }

                // sort
                if (options.OrderByDirection == OrderByDirection.Ascending && options.OrderByExpression != null)
                {
                    results = results.OrderBy(options.OrderByExpression);
                }
                if (options.OrderByDirection == OrderByDirection.Descending && options.OrderByExpression != null)
                {
                    results = results.OrderByDescending(options.OrderByExpression);
                }

                // pagination
                if (options.PageNumber.HasValue && options.ResultsPerPage.HasValue)
                {
                    results = results.Skip((options.PageNumber.Value - 1) * options.ResultsPerPage.Value);
                }
                if (options.ResultsPerPage.HasValue)
                {
                    results = results.Take(options.ResultsPerPage.Value);
                }

                return(results.GetResults());
            }
        }
Ejemplo n.º 17
0
        public static IQueryable <TModel> ApplyOptions <TModel>(
            this IQueryable <TModel> query,
            ISearchOptions options,
            out ISearchOptions appliedOptions)
            where TModel : IQueryModel
        {
            if (options == null)
            {
                appliedOptions = null;

                return(query);
            }

            var propertiesToSearch = ReflectionHelper
                                     .GetPropertyNamesThatAllowSearch <TModel>();

            appliedOptions =
                new SearchOptions
            {
                PropertyNames =
                    (options.PropertyNames ?? Enumerable.Empty <string>())
                    .Where(
                        name => propertiesToSearch.Contains(name))
                    .ToList(),
                Term = options.Term
            };

            if (!appliedOptions.PropertyNames.Any() ||
                string.IsNullOrEmpty(appliedOptions.Term))
            {
                return(query);
            }

            var searchExpression = ReflectionHelper
                                   .CreateSearchExpressionFor <TModel>(
                appliedOptions.PropertyNames, appliedOptions.Term);

            return(query.Where(searchExpression));
        }
        protected internal virtual IEnumerable <string> GetAttributes(ISearchOptions searchOptions)
        {
            if (searchOptions == null)
            {
                throw new ArgumentNullException("searchOptions");
            }

            switch (searchOptions.AttributesSetting)
            {
            case AttributesSetting.Identity:
                return(this.DirectorySettings.IdentityAttributes);

            case AttributesSetting.Minimum:
                return(this.DirectorySettings.MinimumNumberOfAttributes);

            case AttributesSetting.None:
                return(this.DirectorySettings.NoExistingAttributes);

            default:
                return(searchOptions.Attributes);
            }
        }
Ejemplo n.º 19
0
        public P4kFileSystemViewModel(IFileSystem fileSystem,
                                      ICurrentItem currentItem,
                                      IPinnedItems selectedItems,
                                      IExtractP4kContent extractP4KContent,
                                      ISearch search,
                                      ISearchOptions searchOptions,
                                      IUiDispatch uiDispatch,
                                      IEnumerable <IFileSubStructureProvider> subFileFactories)
        {
            _fileSystem        = fileSystem;
            _currentItem       = currentItem;
            _selectedItems     = selectedItems;
            _extractP4KContent = extractP4KContent;
            _search            = search;
            _searchOptions     = searchOptions;
            _uiDispatch        = uiDispatch;
            _subFileFactories  = subFileFactories.ToArray();
            RootItems          = new ObservableCollection <TreeNodeViewModel>();

            SetCurrentItemCommand               = new RelayCommand <object>(SetCurrentItem);
            SetCurrentFileToNothingCommand      = new RelayCommand(_currentItem.Clear);
            ToggleSelectionOfCurrentItemCommand = new RelayCommand(ToggleSelectionOfCurrentItem);
            ExtractCommand = new RelayCommand <object>(ExtractItem);

            ExpandCommand = new RelayCommand <object>(async p =>
            {
                if (!(p is DirectoryTreeNodeViewModel directory))
                {
                    return;
                }

                await directory.LoadChildrenAsync();
            });

            CreateRootItems();

            _search.Finished       += FilterRootItems;
            _search.ResultsCleared += CreateRootItems;
        }
Ejemplo n.º 20
0
        public DirectoryTreeNodeViewModel(IDirectory directory,
                                          ISearch search,
                                          ISearchOptions searchOptions,
                                          IUiDispatch uiDispatch,
                                          IEnumerable <IFileSubStructureProvider> subFileFactories)
            : base(directory.Name, directory.Path)
        {
            Model                   = directory;
            _search                 = search;
            _searchOptions          = searchOptions;
            _uiDispatch             = uiDispatch;
            _subFileFactories       = subFileFactories;
            _search.Finished       += FilterContent;
            _search.Finished       += HighlightSearchTerm;
            _search.ResultsCleared += ResetName;
            _search.Began          += ResetChildren;

            //if (!Model.IsEmpty)
            //{
            //  ResetChildren();
            //}
            HighlightSearchTerm();
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Returns the <see cref="ISearcher"/> as specified by the specified <paramref name="options"/>.
        ///
        /// If <paramref name="options"/> doesn't specify a searcher, the searcher of <c>ExternalIndex</c> will be used as fallback.
        /// </summary>
        /// <param name="options">The search options.</param>
        /// <returns>The <see cref="ISearcher"/> to be used for the search.</returns>
        protected virtual ISearcher GetSearcher(ISearchOptions options)
        {
            ISearcher searcher;

            switch (options)
            {
            case ISearcherOptions searcherOptions:
                searcher = searcherOptions.Searcher;
                if (searcher != null)
                {
                    return(searcher);
                }
                break;

            case IGetSearcherOptions getSearcherOptions:
                searcher = getSearcherOptions.GetSearcher(_examine, this);
                if (searcher != null)
                {
                    return(searcher);
                }
                break;

            default:
                if (_examine.TryGetIndex(ExamineConstants.ExternalIndexName, out IIndex index))
                {
                    searcher = index.GetSearcher();
                    if (searcher != null)
                    {
                        return(searcher);
                    }
                }
                break;
            }

            throw new Exception($"Failed determining searcher from {options.GetType()}");
        }
Ejemplo n.º 22
0
        public async Task <ISearchResult> SearchQueryAsync(string indexName, SearchQuery query, ISearchOptions options = default)
        {
            await EnsureBootstrapped();

            query.Index = indexName;

            if (options == default)
            {
                options = new SearchOptions();
            }
            //TODO: convert options to params

            return(await _lazySearchClient.Value.QueryAsync(query));
        }
 public virtual IEnumerable <SearchResultEntry> GetTree(ISearchOptions searchOptions)
 {
     return(this.GetTree(this.LdapConnectionSettings.DistinguishedName, searchOptions));
 }
        public static string GenerateSearchString(this ISearchOptions searchOptions, IList <object> parameters)
        {
            var sb   = new StringBuilder();
            var type = searchOptions.GetType();

            /***************************************************************************************
             * Create the Select statement. Determine the table name and schema.                   *
             **************************************************************************************/
            var tableAttribute = type.GetCustomAttribute(typeof(TableAttribute)) as TableAttribute;
            var schema         = tableAttribute?.Schema ?? "dbo";
            var tableName      = tableAttribute?.Name ?? searchOptions.GetType().Name.Replace("SearchOptions", "");

            sb.Append($"SELECT * FROM {schema}.{tableName} WHERE ");

            /***************************************************************************************
             * Add the WHERE statements.                                                           *
             **************************************************************************************/
            foreach (var property in type.GetProperties())
            {
                if (!property.CanRead)
                {
                    continue;
                }

                //Ignore the current property if necessary.
                var ignoreAttribute = (IgnoreAttribute)property.GetCustomAttribute(typeof(IgnoreAttribute));

                if (ignoreAttribute?.IsIgnored(SqlAction.Select) == true)
                {
                    continue;
                }

                //Determine the column name.
                var columnAttribute = (Attributes.ColumnAttribute)property.GetCustomAttribute(typeof(Attributes.ColumnAttribute));
                var columnName      = columnAttribute != null
                    ? columnAttribute.Name
                    : property.Name;

                var equalityMethod = columnAttribute != null
                    ? columnAttribute.EqualityMethod
                    : "=";

                if (property.GetValue(searchOptions) != null)
                {
                    var val = property.GetValue(searchOptions);
                    if (val is IEnumerable list)
                    {
                        switch (list.Count())
                        {
                        case 0:
                            sb.Append("1=0");
                            break;

                        case 1:
                            sb.Append($"{columnName} = {{{parameters.Count}}}");
                            parameters.Add(list.FirstOrDefault());
                            break;

                        default:
                            sb.Append($"{columnName} IN ({{{parameters.Count}}})");
                            parameters.Add(list);
                            break;
                        }
                    }
                    else if (property.GetValue(searchOptions) is string str)
                    {
                        if (!string.IsNullOrEmpty(str))
                        {
                            switch (equalityMethod)
                            {
                            case "LIKE":
                                sb.Append($"{columnName} LIKE {{{parameters.Count}}}");
                                parameters.Add($"%{str}%");
                                break;

                            case "=":
                                sb.Append($"{columnName} = {{{parameters.Count}}}");
                                parameters.Add(str);
                                break;
                            }
                        }
                    }
                    else
                    {
                        sb.Append($"{columnName} {equalityMethod} {{{parameters.Count}}}");
                        parameters.Add(property.GetValue(searchOptions));
                    }


                    sb.Append(" AND ");
                }
            }

            sb.Length -= sb.ToString().EndsWith(" WHERE ")
                ? 7
                : 5;

            return(sb.ToString());
        }
Ejemplo n.º 25
0
        public Task <ISearchResult> SearchQueryAsync(string indexName, SearchQuery query, ISearchOptions options = default)
        {
            if (_searchClient == null)
            {
                _searchClient = new SearchClient(_configuration);
            }

            query.Index = indexName;

            if (options == default)
            {
                options = new SearchOptions();
            }
            //TODO: convert options to params

            return(_searchClient.QueryAsync(query));
        }
 public virtual IEnumerable <SearchResultEntry> GetTree(string identity, ISearchOptions searchOptions)
 {
     return(this.GetSearchResult(identity, searchOptions, SearchScope.Subtree, this.DirectorySettings.PageSize));
 }
Ejemplo n.º 27
0
 public UrlParameterBuilder(ISearchOptions options)
 {
     Options = options;
 }
Ejemplo n.º 28
0
 /// <summary>
 /// Creates a new query from the specified <paramref name="searcher"/> and <paramref name="options"/>.
 /// </summary>
 /// <param name="searcher">The searcher.</param>
 /// <param name="options">The options for the search.</param>
 /// <returns>An instance of <see cref="IQuery"/>.</returns>
 protected virtual IQuery CreateQuery(ISearcher searcher, ISearchOptions options)
 {
     return(searcher.CreateQuery());
 }
Ejemplo n.º 29
0
 public Search(ICurrentP4k currentP4K,
               ISearchOptions searchOptions)
 {
     _currentP4K    = currentP4K;
     _searchOptions = searchOptions;
 }
Ejemplo n.º 30
0
        public static IQueryable <T> ApplySearch <T>(this IQueryable <T> query, ISearchOptions options)
        {
            if (options?.Search?.Length > 0)
            {
                var _searchQuery      = options.Search;
                var searchQueryLength = _searchQuery.Length;

                // get given type's all properties
                var properties       = typeof(T).GetProperties();
                var propertiesLength = properties.Length;

                // iterate over all terms
                for (int i = 0; i < searchQueryLength; i++)
                {
                    if (string.IsNullOrEmpty(_searchQuery[i]))
                    {
                        continue;
                    }

                    // expression -> name eq shahid
                    var tokens = _searchQuery[i].Split(' ');
                    if (tokens.Length == 3)
                    {
                        string @operator = tokens[1];
                        string value     = tokens[2];

                        for (int j = 0; j < propertiesLength; j++)
                        {
                            // if property has sortable attribute and sort term equals to property name
                            var  searchableAttribute = properties[j].GetCustomAttributes <SearchableAttribute>().FirstOrDefault();
                            bool isSearchable        = searchableAttribute != null && properties[j].Name.Equals(tokens[0], StringComparison.OrdinalIgnoreCase);

                            if (isSearchable)
                            {
                                // build up the LINQ expression backwards:
                                // query = query.Where(x => x.Property == "Value");

                                var parameter = ExpressionHelper.Parameter <T>();

                                // x.Property
                                var left = ExpressionHelper.GetPropertyExpression(parameter, properties[j]);

                                // "Value"
                                var right = GetConstantExpression(tokens[2], searchableAttribute.Type);

                                // x.Property == "Value"
                                var comparisonExpression = GetComparisonExpression(left, tokens[1], right);

                                // x => x.Property == "Value"
                                var lambda = ExpressionHelper
                                             .GetLambda <T, bool>(parameter, comparisonExpression);

                                // query = query.Where...
                                query = ExpressionHelper.CallWhere(query, lambda);
                            }
                        }
                    }
                }
            }
            return(query);
        }
Ejemplo n.º 31
0
        public static IQueryable <T> ApplySearch <T>(this IQueryable <T> query, ISearchOptions options)
        {
            if (options?.Search?.Length > 0)
            {
                if (_utilitiesOptions == null)
                {
                    _utilitiesOptions = SearchUtilitiesOptions.DefaultOptions;
                    _comparisonExpressionProviderFactory = _utilitiesOptions.ComparisonExpressionProviderFactory;
                }

                var _searchQuery      = options.Search;
                var searchQueryLength = _searchQuery.Length;

                // get given type's all properties
                var properties       = typeof(T).GetProperties();
                var propertiesLength = properties.Length;

                // iterate over all terms
                for (int i = 0; i < searchQueryLength; i++)
                {
                    if (string.IsNullOrEmpty(_searchQuery[i]))
                    {
                        continue;
                    }

                    // expression -> name eq shahid
                    var tokens = _searchQuery[i].Split(' ');
                    if (tokens.Length > 3)
                    {
                        // remove null or empty items
                        tokens = tokens.Where(x => !string.IsNullOrEmpty(x)).ToArray();
                    }
                    if (tokens.Length == 3)
                    {
                        string @operator = tokens[1];
                        string value     = tokens[2];

                        for (int j = 0; j < propertiesLength; j++)
                        {
                            // if property has sortable attribute and sort term equals to property name
                            var  searchableAttribute = properties[j].GetCustomAttributes <SearchableAttribute>().FirstOrDefault();
                            bool isSearchable        = searchableAttribute != null && properties[j].Name.Equals(tokens[0], StringComparison.OrdinalIgnoreCase);

                            if (isSearchable)
                            {
                                // build up the LINQ expression backwards:
                                // query = query.Where(x => x.Property == "Value");

                                var parameter = ExpressionUtilities.Parameter <T>();

                                // x.Property
                                var left = parameter.GetPropertyExpression(properties[j]);

                                // "Value"
                                var constantValue = Convert.ChangeType(tokens[2], properties[j].PropertyType);
                                var right         = Expression.Constant(constantValue);

                                // x.Property == "Value"
                                var comparisonExpressionProvider = _comparisonExpressionProviderFactory.CreateProvider(tokens[1].ToLower());
                                var comparisonExpression         = comparisonExpressionProvider.GetExpression(left, right);

                                // x => x.Property == "Value"
                                var lambda = ExpressionUtilities
                                             .GetLambda <T, bool>(parameter, comparisonExpression);

                                // query = query.Where...
                                query = query.DynamicWhere(lambda);
                            }
                        }
                    }
                }
            }
            return(query);
        }