/// <summary> /// Parses a Boolean search query to produce an IQueryComponent for that query. /// </summary> /// <param name="query">query to be parsed to a query component</param> /// <returns>a query component</returns> public IQueryComponent ParseQuery(String query) { // General routine: scan the query to identify a literal, and put that literal into a list. // Repeat until a + or the end of the query is encountered; build an AND query with each // of the literals found. Repeat the scan-and-build-AND-query phase for each segment of the // query separated by + signs. In the end, build a single OR query that composes all of the built // AND subqueries. if (query == null) { return(null); } query = query.TrimStart(' ').TrimEnd(' '); if (query == "" || query == null) { return(null); } int start = 0; var allSubqueries = new List <IQueryComponent>(); do { // Identify the next subquery: a portion of the query up to the next + sign. StringBounds nextSubquery = FindNextSubquery(query, start); // Extract the identified subquery into its own string. String subquery = query.Substring(nextSubquery.Start, nextSubquery.Length); int subStart = 0; // Store all the individual components of this subquery. var subqueryLiterals = new List <IQueryComponent>(); do { // Extract the next literal from the subquery. Literal lit = FindNextLiteral(subquery, subStart); // Add the literal component to the conjunctive list. subqueryLiterals.Add(lit.LiteralComponent); // Set the next index to start searching for a literal. subStart = lit.Bounds.Start + lit.Bounds.Length; } while (subStart < subquery.Length); // After processing all literals, we are left with a list of query components that we are // ANDing together, and must fold that list into the final OR list of components. // If there was only one literal in the subquery, we don't need to AND it with anything -- // its component can go straight into the list. if (subqueryLiterals.Count == 1) { allSubqueries.Add(subqueryLiterals[0]); } else { // With more than one literal, we must wrap them in an AndQuery component. allSubqueries.Add(new AndQuery(subqueryLiterals)); } start = nextSubquery.Start + nextSubquery.Length; } while (start < query.Length); // After processing all subqueries, we either have a single component or multiple components // that must be combined with an OrQuery. if (allSubqueries.Count == 1) { return(allSubqueries[0]); } else if (allSubqueries.Count > 1) { return(new OrQuery(allSubqueries)); } else { return(null); } }
public Literal(StringBounds bounds, IQueryComponent literal) { Bounds = bounds; LiteralComponent = literal; }