Example #1
0
    private static void Build()
    {
        allTypes = TypeCache.GetTypesDerivedFrom <UnityEngine.Object>().ToArray();

        var sw = new System.Diagnostics.Stopwatch();

        sw.Start();

        QE = new QueryEngine <Type>();
        QE.AddFilter("m", t => t.GetMethods().Length);
        QE.AddFilter("id", t => t.FullName);
        QE.AddFilter("asm", t => Path.GetFileNameWithoutExtension(t.Assembly.Location).ToLowerInvariant());
        QE.SetSearchDataCallback(t => new[] { t.Name });
        Debug.Log($"QuerEngine initialization took {sw.Elapsed.TotalMilliseconds,3:0.##} ms");

        sw.Restart();
        index = new SearchIndexer();
        index.Start();
        foreach (var t in allTypes)
        {
            var di = index.AddDocument(t.AssemblyQualifiedName, false);
            index.AddWord(t.Name.ToLowerInvariant(), 0, di);
            index.AddNumber("m", t.GetMethods().Length, 0, di);
            index.AddProperty("id", t.FullName.ToLowerInvariant(),
                              minVariations: t.FullName.Length, maxVariations: t.FullName.Length,
                              score: 0, documentIndex: di,
                              saveKeyword: false, exact: true);
            index.AddProperty("asm", Path.GetFileNameWithoutExtension(t.Assembly.Location).ToLowerInvariant(), di);
        }
        index.Finish(() => Debug.Log($"Type indexing took {sw.Elapsed.TotalMilliseconds,3:0.##} ms"));
    }
Example #2
0
 static void OnEnable()
 {
     if (s_QueryEngine == null)
     {
         s_QueryEngine = new QueryEngine <ImageData>();
         s_QueryEngine.AddFilter("color", (imageData, context) => GetColorSimilitude(imageData, context), param => GetColorFromParameter(param));
         s_QueryEngine.AddFilter("hist", (imageData, context) => GetHistogramSimilitude(imageData, context), param => GetHistogramFromParameter(param));
         s_QueryEngine.SetSearchDataCallback(DefaultSearchDataCallback);
     }
 }
    static void OnEnable()
    {
        s_GameObjects = FetchGameObjects();
        s_QueryEngine = new QueryEngine <GameObject>();

        // Id supports all operators
        s_QueryEngine.AddFilter("id", go => go.GetInstanceID());
        // Name supports only :, = and !=
        s_QueryEngine.AddFilter("n", go => go.name, new [] { ":", "=", "!=" });

        // Add distance filtering. Does not support :.
        s_QueryEngine.AddFilter("dist", DistanceHandler, DistanceParamHandler, new [] { "=", "!=", "<", ">", "<=", ">=" });
    }
        public SceneQueryEngine(GameObject[] gameObjects)
        {
            m_GameObjects = gameObjects;
            m_QueryEngine.AddFilter("id", GetId);
            m_QueryEngine.AddFilter("path", GetPath);
            m_QueryEngine.AddFilter("tag", GetTag);
            m_QueryEngine.AddFilter("layer", GetLayer);
            m_QueryEngine.AddFilter("size", GetSize);
            m_QueryEngine.AddFilter <string>("is", OnIsFilter, new [] { ":" });
            m_QueryEngine.AddFilter <string>("t", OnTypeFilter, new [] { "=", ":" });

            m_QueryEngine.AddFilter("p", OnPropertyFilter, s => s, StringComparison.OrdinalIgnoreCase);

            m_QueryEngine.AddOperatorHandler(":", (object v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => r.Contains(f)));
            m_QueryEngine.AddOperatorHandler("=", (object v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => r.Contains(f)));
            m_QueryEngine.AddOperatorHandler("!=", (object v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => !r.Contains(f)));
            m_QueryEngine.AddOperatorHandler("<=", (object v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => f <= r.max));
            m_QueryEngine.AddOperatorHandler("<", (object v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => f < r.min));
            m_QueryEngine.AddOperatorHandler(">", (object v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => f > r.max));
            m_QueryEngine.AddOperatorHandler(">=", (object v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => f >= r.min));

            m_QueryEngine.AddTypeParser(arg =>
            {
                if (arg.Length > 0 && arg.Last() == ']')
                {
                    var rangeMatches = s_RangeRx.Matches(arg);
                    if (rangeMatches.Count == 1 && rangeMatches[0].Groups.Count == 3)
                    {
                        var rg = rangeMatches[0].Groups;
                        if (float.TryParse(rg[1].Value, out var min) && float.TryParse(rg[2].Value, out var max))
                        {
                            return(new ParseResult <PropertyRange>(true, new PropertyRange(min, max)));
                        }
                    }
                }

                return(ParseResult <PropertyRange> .none);
            });

            m_QueryEngine.AddTypeParser(arg =>
            {
                if (float.TryParse(arg, out var f))
                {
                    return(new ParseResult <object>(true, f));
                }

                if (arg == "true")
                {
                    return(new ParseResult <object>(true, true));
                }
                if (arg == "false")
                {
                    return(new ParseResult <object>(true, false));
                }

                return(new ParseResult <object>(true, arg));
            });

            m_QueryEngine.SetSearchDataCallback(OnSearchData, StringComparison.Ordinal);
        }
                void ICollectionPropertyBagVisitor.Visit <TCollection, TElement>(ICollectionPropertyBag <TCollection, TElement> properties, ref TCollection container)
                {
                    var path = Path;

                    // This query engine filter is provided with two delegates:
                    //
                    // parameterTransformer: This function is responsible for transforming the input string into a strong generic type.
                    //                       this is done via the `TypeConversion` API in properties.
                    //
                    // filterResolver:       This function takes the data for each element being filtered, along with the original token, and the
                    //                       transformed input. The function then applies the filter and returns true or false. In this particular case
                    //                       we want to test equality with each collection element and return true if ANY match.
                    //
                    QueryEngine.AddFilter <TElement, TElement>(Token, (data, _, token, transformedInput) =>
                    {
                        if (!PropertyContainer.TryGetValue <TData, TCollection>(ref data, path, out var collection))
                        {
                            return(false);
                        }

                        if (RuntimeTypeInfoCache <TCollection> .CanBeNull && null == collection)
                        {
                            return(false);
                        }

                        return(collection.Any(e => FilterOperator.ApplyOperator(token, e, transformedInput, QueryEngine.globalStringComparison)));
                    }, s => TypeConversion.Convert <string, TElement>(ref s), FilterOperator.GetSupportedOperators <TElement>());
                }
            static SettingsProviderCache()
            {
                value = FetchSettingsProviders()
                        .Select(provider => new SettingsProviderInfo()
                {
                    path        = provider.settingsPath,
                    label       = provider.label,
                    scope       = provider.scope,
                    searchables = new[] { provider.settingsPath, provider.label }
                    .Concat(provider.keywords)
                    .Where(s => !string.IsNullOrEmpty(s))
                    .Select(s => Utils.FastToLower(s)).ToArray()
                })
                        .ToArray();

                queryEngine = new QueryEngine <SettingsProviderInfo>();
                queryEngine.SetSearchDataCallback(info => info.searchables, s => Utils.FastToLower(s), StringComparison.Ordinal);
                queryEngine.AddFilter("scope", info => info.scope, new[] { ":", "=", "!=", "<", ">", "<=", ">=" });

                queryEngine.AddOperatorHandler(":", (SettingsScope ev, SettingsScope fv, StringComparison sc) => ev.ToString().IndexOf(fv.ToString(), sc) != -1);
                queryEngine.AddOperatorHandler(":", (SettingsScope ev, string fv, StringComparison sc) => ev.ToString().IndexOf(fv, sc) != -1);
                queryEngine.AddOperatorHandler("=", (SettingsScope ev, SettingsScope fv) => ev == fv);
                queryEngine.AddOperatorHandler("!=", (SettingsScope ev, SettingsScope fv) => ev != fv);
                queryEngine.AddOperatorHandler("<", (SettingsScope ev, SettingsScope fv) => ev < fv);
                queryEngine.AddOperatorHandler(">", (SettingsScope ev, SettingsScope fv) => ev > fv);
                queryEngine.AddOperatorHandler("<=", (SettingsScope ev, SettingsScope fv) => ev <= fv);
                queryEngine.AddOperatorHandler(">=", (SettingsScope ev, SettingsScope fv) => ev >= fv);
            }
        void SetupQueryEngine()
        {
            m_QueryEngine = new QueryEngine <SerializedProperty>();
            m_QueryEngine.SetSearchDataCallback(GetSearchData, s => s.ToLowerInvariant(), StringComparison.Ordinal);

            m_QueryEngine.AddFilter("t", FetchType, StringComparison.Ordinal, new[] { ":" });
            m_QueryEngine.AddTypeParser(s => new ParseResult <string>(true, s.ToLowerInvariant()));
        }
Example #8
0
        internal static SearchProvider CreateProvider()
        {
            List <string> itemNames = new List <string>();
            List <string> shortcuts = new List <string>();

            GetMenuInfo(itemNames, shortcuts);

            System.Threading.Tasks.Task.Run(() => BuildMenus(itemNames));

            queryEngine = new QueryEngine <MenuData>(k_QueryEngineOptions);
            queryEngine.AddFilter("id", m => m.path);
            queryEngine.SetSearchDataCallback(m => m.words, s => Utils.FastToLower(s), StringComparison.Ordinal);

            debounce = Delayer.Debounce(_ => TriggerBackgroundUpdate(itemNames, shortcuts));

            Menu.menuChanged -= OnMenuChanged;
            Menu.menuChanged += OnMenuChanged;

            return(new SearchProvider(type, displayName)
            {
                priority = 80,
                filterId = "m:",
                showDetailsOptions = ShowDetailsOptions.ListView | ShowDetailsOptions.Actions,

                onEnable = () => shortcutIds = ShortcutManager.instance.GetAvailableShortcutIds().ToArray(),
                onDisable = () => shortcutIds = new string[0],

                fetchItems = FetchItems,

                fetchLabel = (item, context) =>
                {
                    if (item.label == null)
                    {
                        var menuName = Utils.GetNameFromPath(item.id);
                        var enabled = Menu.GetEnabled(item.id);
                        var @checked = Menu.GetChecked(item.id);
                        item.label = $"{menuName}{(enabled ? "" : " (disabled)")} {(@checked ? "\u2611" : "")}";
                    }
                    return item.label;
                },

                fetchDescription = (item, context) =>
                {
                    if (string.IsNullOrEmpty(item.description))
                    {
                        item.description = GetMenuDescription(item.id);
                    }
                    return item.description;
                },

                fetchThumbnail = (item, context) => Icons.shortcut,
                fetchPropositions = (context, options) => FetchPropositions(context, options)
            });
        }
Example #9
0
    public QueryEngineBasic()
    {
        GenerateData(1000);

        // Setup the query engine
        m_QueryEngine = new QueryEngine <MyObjectType>();
        // Id supports all operators
        m_QueryEngine.AddFilter("id", myObj => myObj.Id);
        // Name supports only contains (:), equal (=) and not equal (!=)
        m_QueryEngine.AddFilter("n", myObj => myObj.Name, new [] { ":", "=", "!=" });
        // Active supports only equal and not equal
        m_QueryEngine.AddFilter("a", myObj => myObj.Active, new [] { "=", "!=" });
        // The magnitude support equal, not equal, lesser, greater, lesser or equal and greater or equal.
        m_QueryEngine.AddFilter("m", myObj => myObj.Position.magnitude, new [] { "=", "!=", "<", ">", "<=", ">=" });

        // Add a function "dist" to filter item that are at a certain distance from a position or another item
        m_QueryEngine.AddFilter("dist", HandleDistFilter, HandlerDistParameter, new[] { "=", "!=", "<", ">", "<=", ">=" });

        // Setup what data will be matched against search words
        m_QueryEngine.SetSearchDataCallback(myObj => new [] { myObj.Id.ToString(), myObj.Name });
    }
        internal static SearchProvider CreateProvider()
        {
            List <string> itemNames = new List <string>();
            List <string> shortcuts = new List <string>();

            GetMenuInfo(itemNames, shortcuts);

            System.Threading.Tasks.Task.Run(() => BuildMenus(itemNames));

            queryEngine = new QueryEngine <MenuData>(k_QueryEngineOptions);
            queryEngine.AddFilter("id", m => m.path);
            queryEngine.SetSearchDataCallback(m => m.words, s => Utils.FastToLower(s), StringComparison.Ordinal);

            queryEngine.SetNestedQueryHandler((q, f) => q.Split(',').Select(w => w.Trim()));
            queryEngine.SetFilterNestedQueryTransformer <string, string>("id", s => s);

            return(new SearchProvider(type, displayName)
            {
                priority = 80,
                filterId = "m:",
                showDetailsOptions = ShowDetailsOptions.ListView | ShowDetailsOptions.Actions,

                onEnable = () => shortcutIds = ShortcutManager.instance.GetAvailableShortcutIds().ToArray(),
                onDisable = () => shortcutIds = new string[0],

                fetchItems = FetchItems,

                fetchLabel = (item, context) =>
                {
                    if (item.label == null)
                    {
                        var menuName = Utils.GetNameFromPath(item.id);
                        var enabled = Menu.GetEnabled(item.id);
                        var @checked = Menu.GetChecked(item.id);
                        item.label = $"{menuName}{(enabled ? "" : " (disabled)")} {(@checked ? "\u2611" : "")}";
                    }
                    return item.label;
                },

                fetchDescription = (item, context) =>
                {
                    if (string.IsNullOrEmpty(item.description))
                    {
                        item.description = GetMenuDescription(item.id);
                    }
                    return item.description;
                },

                fetchThumbnail = (item, context) => Icons.shortcut
            });
        }
 public SceneQueryEngine(GameObject[] gameObjects)
 {
     m_GameObjects = gameObjects;
     m_QueryEngine.AddFilter("id", GetId);
     m_QueryEngine.AddFilter("path", GetPath);
     m_QueryEngine.AddFilter("tag", GetTag);
     m_QueryEngine.AddFilter("layer", GetLayer);
     m_QueryEngine.AddFilter("size", GetSize);
     m_QueryEngine.AddFilter <string>("is", OnIsFilter, new [] { ":" });
     m_QueryEngine.AddFilter <string>("t", OnTypeFilter, new [] { "=", ":" });
     m_QueryEngine.SetSearchDataCallback(OnSearchData);
     m_QueryEngine.SetGlobalStringComparisonOptions(StringComparison.Ordinal);
 }
Example #12
0
        static void AddTypedFilter <T>(IMatchOperation matchOperation)
        {
            var typedMatchOperation = (MatchOperation <T>)matchOperation;

            s_QueryEngine.AddFilter(typedMatchOperation.matchToken, typedMatchOperation.getFilterData);
        }
Example #13
0
        internal static SearchProvider CreateProvider()
        {
            List <string> itemNames = new List <string>();
            List <string> shortcuts = new List <string>();

            GetMenuInfo(itemNames, shortcuts);

            for (int i = 0; i < itemNames.Count; ++i)
            {
                var menuItem = itemNames[i];
                menus.Add(new MenuData()
                {
                    path  = menuItem,
                    words = SplitMenuPath(menuItem).Concat(new string[] { menuItem }).Select(w => w.ToLowerInvariant()).ToArray()
                });
            }

            queryEngine = new QueryEngine <MenuData>();
            queryEngine.AddFilter("id", m => m.path);
            queryEngine.SetSearchDataCallback(m => m.words, s => s.ToLowerInvariant(), StringComparison.Ordinal);

            queryEngine.SetNestedQueryHandler((q, f) => q.Split(',').Select(w => w.Trim()));
            queryEngine.SetFilterNestedQueryTransformer <string, string>("id", s => s);

            return(new SearchProvider(type, displayName)
            {
                priority = 80,
                filterId = "me:",

                onEnable = () =>
                {
                    shortcutIds = ShortcutManager.instance.GetAvailableShortcutIds().ToArray();
                },

                onDisable = () =>
                {
                    shortcutIds = new string[0];
                },

                fetchItems = (context, items, provider) =>
                {
                    var query = queryEngine.Parse(context.searchQuery);
                    if (!query.valid)
                    {
                        return null;
                    }
                    return query.Apply(menus).Select(m => provider.CreateItem(m.path));
                },

                fetchLabel = (item, context) =>
                {
                    return item.label ?? (item.label = Utils.GetNameFromPath(item.id));
                },

                fetchDescription = (item, context) =>
                {
                    if (String.IsNullOrEmpty(item.description))
                    {
                        item.description = GetMenuDescription(item.id);
                    }
                    return item.description;
                },

                fetchThumbnail = (item, context) => Icons.shortcut
            });
        }
Example #14
0
        public SceneQueryEngine(GameObject[] gameObjects)
        {
            m_GameObjects = gameObjects;
            m_QueryEngine.AddFilter("id", GetId);
            m_QueryEngine.AddFilter("path", GetPath);
            m_QueryEngine.AddFilter("tag", GetTag);
            m_QueryEngine.AddFilter("layer", GetLayer);
            m_QueryEngine.AddFilter("size", GetSize);
            m_QueryEngine.AddFilter <string>("is", OnIsFilter, new [] { ":" });
            m_QueryEngine.AddFilter <string>("t", OnTypeFilter, new [] { "=", ":" });
            m_QueryEngine.AddFilter <string>("ref", GetReferences, new [] { "=", ":" });

            m_QueryEngine.AddFilter("p", OnPropertyFilter, s => s, StringComparison.OrdinalIgnoreCase);

            m_QueryEngine.AddOperatorHandler(":", (GOP v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => r.Contains(f)));
            m_QueryEngine.AddOperatorHandler("=", (GOP v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => r.Contains(f)));
            m_QueryEngine.AddOperatorHandler("!=", (GOP v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => !r.Contains(f)));
            m_QueryEngine.AddOperatorHandler("<=", (GOP v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => f <= r.max));
            m_QueryEngine.AddOperatorHandler("<", (GOP v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => f < r.min));
            m_QueryEngine.AddOperatorHandler(">", (GOP v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => f > r.max));
            m_QueryEngine.AddOperatorHandler(">=", (GOP v, PropertyRange range) => PropertyRangeCompare(v, range, (f, r) => f >= r.min));

            m_QueryEngine.AddOperatorHandler(":", (GOP v, float number, StringComparison sc) => PropertyFloatCompare(v, number, (f, r) => StringContains(f, r, sc)));
            m_QueryEngine.AddOperatorHandler("=", (GOP v, float number) => PropertyFloatCompare(v, number, (f, r) => Math.Abs(f - r) < Mathf.Epsilon));
            m_QueryEngine.AddOperatorHandler("!=", (GOP v, float number) => PropertyFloatCompare(v, number, (f, r) => Math.Abs(f - r) >= Mathf.Epsilon));
            m_QueryEngine.AddOperatorHandler("<=", (GOP v, float number) => PropertyFloatCompare(v, number, (f, r) => f <= r));
            m_QueryEngine.AddOperatorHandler("<", (GOP v, float number) => PropertyFloatCompare(v, number, (f, r) => f < r));
            m_QueryEngine.AddOperatorHandler(">", (GOP v, float number) => PropertyFloatCompare(v, number, (f, r) => f > r));
            m_QueryEngine.AddOperatorHandler(">=", (GOP v, float number) => PropertyFloatCompare(v, number, (f, r) => f >= r));

            m_QueryEngine.AddOperatorHandler("=", (GOP v, bool b) => PropertyBoolCompare(v, b, (f, r) => f == r));
            m_QueryEngine.AddOperatorHandler("!=", (GOP v, bool b) => PropertyBoolCompare(v, b, (f, r) => f != r));

            m_QueryEngine.AddOperatorHandler(":", (GOP v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => StringContains(f, r, sc)));
            m_QueryEngine.AddOperatorHandler("=", (GOP v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Equals(f, r, sc)));
            m_QueryEngine.AddOperatorHandler("!=", (GOP v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => !string.Equals(f, r, sc)));
            m_QueryEngine.AddOperatorHandler("<=", (GOP v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) <= 0));
            m_QueryEngine.AddOperatorHandler("<", (GOP v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) < 0));
            m_QueryEngine.AddOperatorHandler(">", (GOP v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) > 0));
            m_QueryEngine.AddOperatorHandler(">=", (GOP v, string s, StringComparison sc) => PropertyStringCompare(v, s, (f, r) => string.Compare(f, r, sc) >= 0));

            m_QueryEngine.AddTypeParser(arg =>
            {
                if (arg.Length > 0 && arg.Last() == ']')
                {
                    var rangeMatches = s_RangeRx.Matches(arg);
                    if (rangeMatches.Count == 1 && rangeMatches[0].Groups.Count == 3)
                    {
                        var rg = rangeMatches[0].Groups;
                        if (float.TryParse(rg[1].Value, out var min) && float.TryParse(rg[2].Value, out var max))
                        {
                            return(new ParseResult <PropertyRange>(true, new PropertyRange(min, max)));
                        }
                    }
                }

                return(ParseResult <PropertyRange> .none);
            });

            m_QueryEngine.SetSearchDataCallback(OnSearchData, s => s.ToLowerInvariant(), StringComparison.Ordinal);
            m_QueryEngine.AddFiltersFromAttribute <SceneQueryEngineFilterAttribute, SceneQueryEngineParameterTransformerAttribute>();
        }
    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);
    }