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);
    }