using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Search;
using UnityEngine;
static class Example_QueryEngine_AddOperatorHandler
{
static List<MyObjectType> s_Data;
[MenuItem("Examples/QueryEngine/AddOperatorHandler")]
public static void RunExample()
{
// Set up the query engine
var queryEngine = new QueryEngine<MyObjectType>();
queryEngine.AddFilter("id", myObj => myObj.id);
queryEngine.AddFilter("prop", myObj => myObj.property);
queryEngine.SetSearchDataCallback(myObj => new[] { myObj.id.ToString(), myObj.name });
// Set the global string comparison options (default is OrdinalIgnoreCase)
queryEngine.SetGlobalStringComparisonOptions(StringComparison.Ordinal);
// Define new handlers for existing operators, but with new types
queryEngine.AddOperatorHandler("=", (Property ev, int fv) => HandleIntType(ev, fv, (propValue, filterValue) => propValue == filterValue));
queryEngine.AddOperatorHandler("!=", (Property ev, int fv) => HandleIntType(ev, fv, (propValue, filterValue) => propValue != filterValue));
queryEngine.AddOperatorHandler("<", (Property ev, int fv) => HandleIntType(ev, fv, (propValue, filterValue) => propValue < filterValue));
queryEngine.AddOperatorHandler(">", (Property ev, int fv) => HandleIntType(ev, fv, (propValue, filterValue) => propValue > filterValue));
queryEngine.AddOperatorHandler("<=", (Property ev, int fv) => HandleIntType(ev, fv, (propValue, filterValue) => propValue <= filterValue));
queryEngine.AddOperatorHandler(">=", (Property ev, int fv) => HandleIntType(ev, fv, (propValue, filterValue) => propValue >= filterValue));
// New handlers with support for the global string comparison options
queryEngine.AddOperatorHandler(":", (Property ev, string fv, StringComparison options) => HandleStringType(ev, fv, (propValue, filterValue) => propValue.IndexOf(filterValue, options) >= 0));
queryEngine.AddOperatorHandler("=", (Property ev, string fv, StringComparison options) => HandleStringType(ev, fv, (propValue, filterValue) => propValue.Equals(filterValue, options)));
queryEngine.AddOperatorHandler("!=", (Property ev, string fv, StringComparison options) => HandleStringType(ev, fv, (propValue, filterValue) => !propValue.Equals(filterValue, options)));
s_Data = new List<MyObjectType>()
{
new MyObjectType { id = 0, property = new Property("size", PropertyType.Integer, 64) },
new MyObjectType { id = 1, property = new Property("size", PropertyType.Integer, 128) },
new MyObjectType { id = 2, property = new Property("tag", PropertyType.String, "item") },
new MyObjectType { id = 3, property = new Property("tag", PropertyType.String, "car item") },
new MyObjectType { id = 3, property = new Property("tag", PropertyType.String, "42") }
};
// Find all items that have a property with an integer value < 100
var query = queryEngine.ParseQuery("prop<100");
var filteredData = query.Apply(s_Data).ToList();
Debug.Assert(filteredData.Count == 1, $"There should be 1 item in the filtered list but found {filteredData.Count} items.");
Debug.Assert(filteredData.Contains(s_Data[0]), "Test 1 should be in the list as its property value is < 100.");
// Find all items that have a property with a string value that contains "Item".
// In this case, since the comparison option is Ordinal, we test the casing.
query = queryEngine.ParseQuery("prop:Item");
filteredData = query.Apply(s_Data).ToList();
Debug.Assert(filteredData.Count == 0, $"There should be 0 item in the filtered list but found {filteredData.Count} items.");
}
static bool HandleIntType(Property prop, int value, Func<int, int, bool> operatorHandler)
{
if (prop.type != PropertyType.Integer)
return false;
if (!(prop.value is int i))
return false;
return operatorHandler(i, value);
}
static bool HandleStringType(Property prop, string value, Func<string, string, bool> operatorHandler)
{
if (prop.type != PropertyType.String)
return false;
if (!(prop.value is string s))
return false;
return operatorHandler(s, value);
}
enum PropertyType
{
Integer,
String
}
struct Property
{
public string name { get; }
public PropertyType type { get; }
public object value { get; set; }
public Property(string name, PropertyType type, object value)
{
this.name = name;
this.type = type;
this.value = value;
}
}
class MyObjectType
{
public int id { get; set; }
public string name { get; set; } = string.Empty;
public Vector2 position { get; set; } = Vector2.zero;
public bool active { get; set; }
public Property property { get; set; }
public override string ToString()
{
return $"({id}, {name}, ({position.x}, {position.y}), {active})";
}
}
}