public QueryEngineCustomOperators() { GenerateData(1000); // Setup the query engine m_QueryEngine = new QueryEngine <MyCustomObjectType>(); // Id supports all operators m_QueryEngine.AddFilter("id", myObj => myObj.Id); // Setup what data will be matched against search words m_QueryEngine.SetSearchDataCallback(myObj => new[] { myObj.Id.ToString() }); // Extend the set of operators and type parsers // Modulo operator will work on all filters that are integers const string moduloOp = "%"; m_QueryEngine.AddOperator(moduloOp); m_QueryEngine.AddOperatorHandler(moduloOp, (int ev, int fv) => ev % fv == 0); // List operator will work on al filters that have an integer as left hand side and // a list of integers as right hand side var listOp = "?"; m_QueryEngine.AddOperator(listOp); m_QueryEngine.AddOperatorHandler(listOp, (int ev, List <int> values) => values.Contains(ev)); // To correctly parse this new type (because it is not supported by default), we add a type parser m_QueryEngine.AddTypeParser(s => { var tokens = s.Split(','); if (tokens.Length == 0) { return(new ParseResult <List <int> >(false, null)); } var numberList = new List <int>(tokens.Length); foreach (var token in tokens) { if (TryConvertValue(token, out int number)) { numberList.Add(number); } else { return(new ParseResult <List <int> >(false, null)); } } return(new ParseResult <List <int> >(true, numberList)); }); // We an also extend existing operators // Position supports =, !=, <, >, <=, >= m_QueryEngine.AddFilter("p", myObj => myObj.Position, new[] { "=", "!=", "<", ">", "<=", ">=" }); // Extend the =, !=, <, >, <=, >= operators to support comparing Vector2's magnitude m_QueryEngine.AddOperatorHandler("=", (Vector2 ev, Vector2 fv) => Math.Abs(ev.magnitude - fv.magnitude) < float.Epsilon); m_QueryEngine.AddOperatorHandler("!=", (Vector2 ev, Vector2 fv) => Math.Abs(ev.magnitude - fv.magnitude) > float.Epsilon); m_QueryEngine.AddOperatorHandler("<", (Vector2 ev, Vector2 fv) => ev.magnitude < fv.magnitude); m_QueryEngine.AddOperatorHandler(">", (Vector2 ev, Vector2 fv) => ev.magnitude > fv.magnitude); m_QueryEngine.AddOperatorHandler("<=", (Vector2 ev, Vector2 fv) => ev.magnitude <= fv.magnitude); m_QueryEngine.AddOperatorHandler(">=", (Vector2 ev, Vector2 fv) => ev.magnitude >= fv.magnitude); // Add a new type parser for Vector2 m_QueryEngine.AddTypeParser(s => { if (!s.StartsWith("[") || !s.EndsWith("]")) { return(new ParseResult <Vector2>(false, Vector2.zero)); } var trimmed = s.Trim('[', ']'); var vectorTokens = trimmed.Split(','); var vectorValues = vectorTokens.Select(token => float.Parse(token, CultureInfo.InvariantCulture.NumberFormat)).ToList(); Assert.AreEqual(vectorValues.Count, 2); var vector = new Vector2(vectorValues[0], vectorValues[1]); return(new ParseResult <Vector2>(true, vector)); }); // If you don't want to add a multitude of operator handlers, you can define // a generic filter handler that will handle all existing operators on a filter m_QueryEngine.AddFilter <string>("is", IsFilterResolver); }