zzzprojects / System.Linq.Dynamic.Core

The .NET Standard / .NET Core version from the System Linq Dynamic functionality.
https://dynamic-linq.net/
Apache License 2.0
1.57k stars 228 forks source link

Still yet ParseException after update from v.1.0.8.18 to 1.0.9.0 or any newer (till 1.3.7) #759

Closed OlegNadymov closed 11 months ago

OlegNadymov commented 11 months ago

1. Description

In continuation of https://github.com/zzzprojects/System.Linq.Dynamic.Core/issues/757

I have more complex string expressions with inner methods with inner string statements, e.g.:

var exp = @"StaticHelper.In(Id, 
StaticHelper.SubSelect(""Identity"", ""LegalPerson"", 
""StaticHelper.In(ParentId, StaticHelper.SubSelect(""""LegalPersonId"""", """"PointSiteTD"""", """"Identity = "" + StaticHelper.ToExpressionString(StaticHelper.Get(""CurrentPlace""), 2) + """""", """"""""))""
, """"))";

The classes:

public static class StaticHelper
{
    public static Guid? GetGuid(string name)
    {
        return Guid.NewGuid();
    }
    public static SqlExpression SubSelect(string columnName, string objectClassName, string filter, string order)
    {
        Expression<Func<User, bool>>? expFilter = null;
        if (filter != null)
        {
            var config = new ParsingConfig
            {
                CustomTypeProvider = new TestCustomTypeProvider()
            };

            expFilter = DynamicExpressionParser.ParseLambda<User, bool>(config, true, filter); // Failed Here!
        }

        return new SqlExpression
        {
            Filter = expFilter
        };
    }

    public static bool In(Guid value, SqlExpression expression)
    {
        return value != Guid.Empty;
    }

    public static Guid First(SqlExpression sqlExpression)
    {
        return Guid.NewGuid();
    }

    public static string ToExpressionString(Guid? value, int subQueryLevel)
    {
        if (value == null) return "NULL";

         var quote = GetQuote(subQueryLevel);
         return $"Guid.Parse({quote}{value}{quote})";
    }

    public static Guid Get(string settingName)
    {
        return Guid.NewGuid();
    }

    private static string GetQuote(int subQueryLevel)
    {
        var quoteCount = (int)Math.Pow(2, subQueryLevel - 1);
        var quote = String.Concat(System.Linq.Enumerable.Repeat("\"", quoteCount));
        return quote;
    }
}

public class SqlExpression
{
    public Expression<Func<User, bool>>? Filter { get; set; }
}

public class User
{
    public Guid Id { get; set; }

    public Guid? ParentId { get; set; }

    public Guid? LegalPersonId { get; set; }

   // other properties
}

The above expression can be parsed on the preview version. But not invoked. I have ParseException during invoke. I've found differencies how the old and the new version parse this expression:

The old version:

{Param_0 => In(Param_0.Id, SubSelect("Identity", "LegalPerson", Concat(Concat("StaticHelper.In(ParentId, StaticHelper.SubSelect("LegalPersonId", "PointSiteTD", "Identity = ", ToExpressionString(GGet("CurrentPlace"), 2)), "", ""))"), ""))}

The new version:

{Param_0 => In(Param_0.Id, SubSelect("Identity", "LegalPerson", Concat(Concat("StaticHelper.In(ParentId, StaticHelper.SubSelect("LegalPersonId"", ""PointSiteTD"", ""Identity = "", ToExpressionString(Get("CurrentPlace"), 2)), "", """"))""), ""))}

Here starting with PointSiteTD statements there are two quotes in the new version instead single in the old version. So, when I try to parse with expression inside StaticHelper.SubSelect to build SqlExpression.Filter I have the mentioned exception.

2. Exception

'System.Linq.Dynamic.Core.Exceptions.ParseException' in System.Linq.Dynamic.Core.dll ("')' or ',' expected")

Exception message:

')' or ',' expected

3. Fiddle or Project

Again, I have done changes in DynamicExpressionParserTests only locally.

4. Any further technical details

It is working on v.1.0.8.18. But it is not working on even version 1.3.8-preview-01.

StefH commented 11 months ago

@OlegNadymov Can you provide the full "User" class?

StefH commented 11 months ago

https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/760

StefH commented 11 months ago

@OlegNadymov I could not test it 100% (due to missing User class), but I've updated the code.

Can you try 1.3.8-preview-02?

StefH commented 11 months ago

you probably need 1.3.8-preview-03

OlegNadymov commented 11 months ago

Unfortunately, again ParseException: ')' or ',' expected.

I see that now inner statements have the same number of quoutes (two):

{Param_0 => In(Param_0.Id, SubSelect("Identity", "LegalPerson", Concat(Concat("StaticHelper.In(ParentId, StaticHelper.SubSelect(""LegalPersonId"", ""PointSiteTD"", ""Identity = ", ToExpressionString(Get("CurrentPlace"), 2)), """, """"))"), ""))}

But in the old version they had one single quote:

{Param_0 => In(Param_0.Id, SubSelect("Identity", "LegalPerson", Concat(Concat("StaticHelper.In(ParentId, StaticHelper.SubSelect("LegalPersonId", "PointSiteTD", "Identity = ", ToExpressionString(Get("CurrentPlace"), 2)), "", ""))"), ""))}

So, when I try to DynamicInvoke the complied expression I have the exception here: image image

BTW, I use the same User class from your tests, but I've added new three properties as you did here: https://github.com/zzzprojects/System.Linq.Dynamic.Core/pull/760

StefH commented 11 months ago

Can you try preview-4?

OlegNadymov commented 11 months ago

It seems to be working now 👍

StefH commented 11 months ago

Thanks for verifying. Please do some more tests, and if it's working good, close this issue.

OlegNadymov commented 11 months ago

Ok! I'm trying to check if it works for a deeper level. I think, I don't have expressions with deeper levels. But I'm wondering if it works.

OlegNadymov commented 11 months ago

All my tests are passed successfully. So, I will be looking forward for release these features to upgrade your package on my production.

StefH commented 9 months ago

@OlegNadymov I'll merge this PR to master.

I've no date yet on a new release. I'll keep you informed.

OlegNadymov commented 9 months ago

@StefH thanks for the information! 👍