Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IN style operator #135

Closed
alirezanet opened this issue Nov 8, 2023 Discussed in #133 · 5 comments
Closed

IN style operator #135

alirezanet opened this issue Nov 8, 2023 Discussed in #133 · 5 comments
Labels
enhancement New feature or request

Comments

@alirezanet
Copy link
Owner

alirezanet commented Nov 8, 2023

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

@alirezanet alirezanet added feature-request enhancement New feature or request and removed feature-request labels Nov 8, 2023
@alirezanet
Copy link
Owner Author

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

@sjblack
Copy link

sjblack commented Nov 12, 2023

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]'.

@alirezanet alirezanet reopened this Nov 12, 2023
@alirezanet
Copy link
Owner Author

hi @sjblack,
Oh weird! can you share your operator?

@alirezanet
Copy link
Owner Author

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

@sjblack
Copy link

sjblack commented Nov 13, 2023

Apologises I made a very silly mistake, couldn't see the wood for the tree. Works a treat, thank you very much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants