IN style operator
Closed this issue · 5 comments
Discussed in #133
We need to generate something like this:
'SELECT State FROM Tasks WHERE State IN (guid1, guid2)'
also CustomOperator for this purpose is not working:
GridifyGlobalConfiguration.CustomOperators.Register(new InOperator());
var repo = new List<TestTask>()
{
new() { State = 1 },
new() { State = 2 },
new() { State = 3 },
new() { State = 4 },
}.AsQueryable();
var qb = new QueryBuilder<TestTask>()
.AddMap("state", q=> q.State, value => value.Split(";").Select(int.Parse).ToList())
.AddCondition("state#=2;4;6")
.Build(repo)
.Dump();
class InOperator : IGridifyOperator
{
public string GetOperator() => "#=";
public Expression<OperatorParameter> OperatorHandler()
{
return (prop, value) => ((IList)value).Contains((int)prop);
}
}
class TestTask
{
public int State { get; set; }
}
Error:
ArgumentException•••
Argument types do not match
in v2.13.1
, Custom operators can support type casting so now it is possible to create an In
operator if needed.
e.g:
class InOperator: IGridifyOperator
{
public string GetOperator()
{
return "#In";
}
public Expression<OperatorParameter> OperatorHandler()
{
return (prop, value) => value.ToString()
.Split(";",StringSplitOptions.RemoveEmptyEntries)
.Contains(prop.ToString());
}
}
Or if you need to only support a specific type you can parse it using GridifyMapper's third overload, which is value converter:
e.g for int:
var fitler = "state#In2;4;6";
// Here we are converting the value to a List<int>
mapper.AddMap("state", q => q.State, value => value.Split(";").Select(int.Parse).ToList())
internal class IntInOperator : IGridifyOperator
{
public string GetOperator()
{
return "#In";
}
public Expression<OperatorParameter> OperatorHandler()
{
return (prop, value) => ((List<int>)value).Contains((int)prop);
}
}
Hello, Thank you for this update!
I have tried the second example using Guid's instead of integer's and I get the following error:
System.InvalidOperationException : No coercion operator is defined between types 'System.Guid' and 'System.Collections.Generic.List`1[System.Guid]'.
hi @sjblack,
Oh weird! can you share your operator?
I created a simple test project and it worked as expected, 🤔 ... maybe you forgot to update to the latest version. v2.13.1
?
GridifyGlobalConfiguration.CustomOperators.Register<GuidInOperator>();
var targetGuid = Guid.NewGuid();
var repo = new List<TestTask>()
{
new() { State = targetGuid },
new() { State = Guid.NewGuid() },
new() { State = Guid.NewGuid() },
new() { State = Guid.NewGuid() },
}.AsQueryable();
var ids = new List<Guid> { Guid.NewGuid(), targetGuid, Guid.NewGuid() };
var expected = repo.Where(x => ids.Contains(x.State)).ToList();
// act
var actual = new QueryBuilder<TestTask>()
.AddMap("state", q => q.State,
value => value.Split(";", StringSplitOptions.RemoveEmptyEntries).Select(Guid.Parse).ToList())
.AddCondition($"state #In {Guid.NewGuid()};{Guid.NewGuid()};{targetGuid}")
.Build(repo)
.ToList();
Debug.Assert(actual.Count == 1);
actual.Dump();
class GuidInOperator : IGridifyOperator
{
public string GetOperator()
{
return "#In";
}
public Expression<OperatorParameter> OperatorHandler()
{
return (prop, value) => ((List<Guid>)value).Contains((Guid)prop);
}
}
internal class TestTask
{
public Guid State { get; set; }
}
Apologises I made a very silly mistake, couldn't see the wood for the tree. Works a treat, thank you very much!