nreco / lambdaparser

Runtime parser for string expressions (formulas, method calls). Builds dynamic LINQ expression tree and compiles it to lambda delegate.
http://www.nrecosite.com/
MIT License
309 stars 55 forks source link

Error - Filter Datatable with LINQ inside the .Eval function #32

Closed T0BiD closed 3 years ago

T0BiD commented 3 years ago

Hi,

after a lot of searching I came across this package which seemed perfect for what I needed.

I'm basically trying to filter a DataTable with a LINQ query that's been generated in runtime.

Imagine I have the DataTable dtToFilter, I'd do something like this: (From row In dtToFilter.AsEnumerable Where row("Name").ToString.StartsWith("A") OR row("Name").ToString.StartsWith("B") AND row("Age").ToString = "18" AND row("Occupation").ToString.Contains("rpa") Select row).CopyToDataTable

In my case, the above code is generated an therefore available in a string variable (filterString). My idea was to use your package like this:

Dim lambdaParser As NReco.Linq.LambdaParser = New NReco.Linq.LambdaParser()
Dim context As New Dictionary(Of String, Object)
context.Add("dtToFilter", dtToFilter)
output = lambdaParser.Eval(filterString, context)

Unfortunately it throws the following error:

 NReco.Linq.LambdaParserException: Expected ')' at 5: (From row In dtToFilter.AsEnumerable Where row("Name").ToString.StartsWith("A") OR row("Name").ToString.StartsWith("B") AND row("Age").ToString = "18" AND row("Occupation").ToString.Contains("rpa") Select row).CopyToDataTable 
   at NReco.Linq.LambdaParser.ParseValue(String expr, Int32 start)
   at NReco.Linq.LambdaParser.ParsePrimary(String expr, Int32 start)
   at NReco.Linq.LambdaParser.ParseUnary(String expr, Int32 start)
   at NReco.Linq.LambdaParser.ParseMultiplicative(String expr, Int32 start)
   at NReco.Linq.LambdaParser.ParseAdditive(String expr, Int32 start)
   at NReco.Linq.LambdaParser.ParseEq(String expr, Int32 start)
   at NReco.Linq.LambdaParser.ParseAnd(String expr, Int32 start)
   at NReco.Linq.LambdaParser.ParseOr(String expr, Int32 start)
   at NReco.Linq.LambdaParser.ParseConditional(String expr, Int32 start)
   at NReco.Linq.LambdaParser.Parse(String expr)
   at NReco.Linq.LambdaParser.Eval(String expr, Func`2 getVarValue)
   at NReco.Linq.LambdaParser.Eval(String expr, IDictionary`2 vars)
   at UiPathCodeRunner_3e7f94b226e64e9ab40aa7833cf4c058.Run(String filterString, DataTable dtToFilter, Object& output)

Do you have any tips on how to solve this or is this not possible?

Edit: Here's a simple fiddle: https://dotnetfiddle.net/uK5Mbe

VitaliyMF commented 3 years ago

Syntax like "From row In dtToFilter" is not supported -- what is possible to use you may found in the unit test: https://github.com/nreco/lambdaparser/blob/master/src/NReco.LambdaParser.Tests/LambdaParserTests.cs

In short, you may call methods or delegates, get object properties/fields, use boolean & math operators. But you cannot write cycles like for/foreach (this is by design).

Also, if "row" is not a delegate and you want to access values via indexer, valid syntax is C#-like: row["Name"]

T0BiD commented 3 years ago

Thanks for your quick answer
So bascially, what I have in mind is not possible, right?

It's in VB.Net, so row("Name") is valid

VitaliyMF commented 3 years ago

So bascially, what I have in mind is not possible, right?

You may iterate rows in your VB.NET code, and call "Eval" for each row (reference to the row object should be passed to the evaluation context) and in this way to implement a filter with an expression that can be defined in the run-time.

It's in VB.Net, so row("Name") is valid

LambdaParser has its own syntax, there is no any relation to language you use (doesn't matter VB.NET or C#).

T0BiD commented 3 years ago

Alright thanks a lot, I'll look into it further.

Oh ok.. I missed that.