using Microsoft.Search.Interop; namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex { public class QueryConstructor { private Settings Settings { get; } private const string SystemIndex = "SystemIndex"; public CSearchQueryHelper BaseQueryHelper { get; } public QueryConstructor(Settings settings) { Settings = settings; BaseQueryHelper = CreateBaseQuery(); } private CSearchQueryHelper CreateBaseQuery() { var baseQuery = CreateQueryHelper(); // Set the number of results we want. Don't set this property if all results are needed. baseQuery.QueryMaxResults = Settings.MaxResult; // Set list of columns we want to display, getting the path presently baseQuery.QuerySelectColumns = "System.FileName, System.ItemUrl, System.ItemType"; // Filter based on file name baseQuery.QueryContentProperties = "System.FileName"; // Set sorting order //baseQuery.QuerySorting = "System.ItemType DESC"; return baseQuery; } internal static CSearchQueryHelper CreateQueryHelper() { // This uses the Microsoft.Search.Interop assembly var manager = new CSearchManager(); // SystemIndex catalog is the default catalog in Windows var catalogManager = manager.GetCatalog(SystemIndex); // Get the ISearchQueryHelper which will help us to translate AQS --> SQL necessary to query the indexer var queryHelper = catalogManager.GetQueryHelper(); return queryHelper; } private static string TopLevelDirectoryConstraint(string path) => $"directory='file:{path}'"; private static string RecursiveDirectoryConstraint(string path) => $"scope='file:{path}'"; /// /// Set the required WHERE clause restriction to search on the first level of a specified directory. /// public string QueryWhereRestrictionsForTopLevelDirectorySearch(string path) { return QueryWhereRestrictionsFromLocationPath(path, "directory='file:"); } /// /// Set the required WHERE clause restriction to search all files and subfolders of a specified directory. /// public string QueryWhereRestrictionsForTopLevelDirectoryAllFilesAndFoldersSearch(string path) { return QueryWhereRestrictionsFromLocationPath(path, "directory='scope:"); } private string QueryWhereRestrictionsFromLocationPath(string path, string searchDepth) { if (path.EndsWith(Constants.DirectorySeperator)) return searchDepth + $"{path}'"; var indexOfSeparator = path.LastIndexOf(Constants.DirectorySeperator); var itemName = path[(indexOfSeparator + 1)..]; if (itemName.StartsWith(Constants.AllFilesFolderSearchWildcard)) itemName = itemName[1..]; var previousLevelDirectory = path.Substring(0, indexOfSeparator); if (string.IsNullOrEmpty(itemName)) return $"{searchDepth}{previousLevelDirectory}'"; return $"(System.FileName LIKE '{itemName}%' OR CONTAINS({FileName},'\"{itemName}*\"',1033)) AND {searchDepth}{previousLevelDirectory}'"; } /// /// Search will be performed on all folders and files on the first level of a specified directory. /// public string Directory(string path, string searchString = "", bool recursive = false) { var queryConstraint = searchString is "" ? "" : $"AND ({FileName} LIKE '{searchString}%' OR CONTAINS({FileName},'\"{searchString}*\"'))"; var scopeConstraint = recursive ? RecursiveDirectoryConstraint(path) : TopLevelDirectoryConstraint(path); string query = $"SELECT TOP {Settings.MaxResult} {BaseQueryHelper.QuerySelectColumns} FROM {SystemIndex} WHERE {scopeConstraint} {queryConstraint} ORDER BY {FileName}"; return query; } /// /// Search will be performed on all folders and files based on user's search keywords. /// public string FilesAndFolders(string userSearchString) { if (string.IsNullOrEmpty(userSearchString)) userSearchString = "*"; // Generate SQL from constructed parameters, converting the userSearchString from AQS->WHERE clause return $"{BaseQueryHelper.GenerateSQLFromUserQuery(userSearchString)} AND {RestrictionsForAllFilesAndFoldersSearch} ORDER BY {FileName}"; } /// /// Set the required WHERE clause restriction to search for all files and folders. /// public const string RestrictionsForAllFilesAndFoldersSearch = "scope='file:'"; /// /// Order identifier: file name /// public const string FileName = "System.FileName"; /// /// Search will be performed on all indexed file contents for the specified search keywords. /// public string FileContent(string userSearchString) { string query = $"SELECT TOP {Settings.MaxResult} {BaseQueryHelper.QuerySelectColumns} FROM {SystemIndex} WHERE {RestrictionsForFileContentSearch(userSearchString)} AND {RestrictionsForAllFilesAndFoldersSearch} ORDER BY {FileName}"; return query; } /// /// Set the required WHERE clause restriction to search within file content. /// public static string RestrictionsForFileContentSearch(string searchQuery) => $"FREETEXT('{searchQuery}')"; } }