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

Request for contribution #230

Closed
david-garcia-garcia opened this issue Nov 27, 2018 · 7 comments
Closed

Request for contribution #230

david-garcia-garcia opened this issue Nov 27, 2018 · 7 comments

Comments

@david-garcia-garcia
Copy link
Contributor

david-garcia-garcia commented Nov 27, 2018

We've been working on a internal tool that converts lambda expressions to text-based expressions that are compatible with this library (System.Linq.Dynamic.Core).

Original implementation was inspired by:

https://github.com/aspnet/Mvc/blob/9c545aa343ccb1bf413888573c398fe56017d9ee/src/Microsoft.AspNet.Mvc.Core/Rendering/Expressions/ExpressionHelper.cs

I think this would be an interesting addition to Dynamic.Linq.Core as it provides a way to convert LambdaExpressions to strings that can be used by Dynamic.Linq.Core.

It's kind of the opposite of what LambdaParser does.

Of course it's a bit more complex (not only converts to string, but extracts the arguments and parameters) that what is shown here, but I just paste relevant usage code so that maintainer can evaluate if a formal PR will have any chance.

An example of part of the test coverage we have for this tool:

           // Binary materialization
            Assert.Equal(
                $"new {typeof(CORE_USER).FullName}(@p0 as name)",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        new CORE_USER() { name = "dtoname" })).Expression);

            // Binary materialization
            Assert.Equal(
                "company.fk_sabentis_businessgroup == @p0",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((SABENTIS_COMPANY company) =>
                        company.fk_sabentis_businessgroup == nullableValue.Value)).Expression);

            // Binary materialization
            Assert.Equal(
                "@p0",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        (a + 2) == 3 ? "yes" : "no")).Expression);

            // Binary materialization
            Assert.Equal(
                "@p0",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        1 + 2)).Expression);

            // Binary not materialized
            Assert.Equal(
                "i.deletedAt + @p0",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        i.deletedAt + 2)).Expression);

            string[] strings = { "a", "b" };

            // Array accesor
            Assert.Equal(
                "@p0",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        strings[0])).Expression);

            // Array accesor II
            Assert.Equal(
                "@p0[i.changedAt]",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        strings[(int)i.changedAt])).Expression);

            // SQL Functions
            Assert.Equal(
                "rootprojection.DBFIELD.field.firstname == rootprojection2.DBFIELD.firstname",
                expVisitor.GetExpressionText(
                        LambdaBuilder.Lambda((CORE_PERSON i, CORE_PERSON i2) => i.firstname == i2.firstname))
                    .SetParameterMapping("i", "rootprojection.DBFIELD.field")
                    .SetParameterMapping("i2", "rootprojection2.DBFIELD")
                    .Expression);

            // SQL Functions
            Assert.Equal(
                "System.Data.Entity.DbFunctions.Like(i.firstname, @p0)",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        DbFunctions.Like(i.firstname, "thename"))).Expression);

            // Negate
            Assert.Equal(
                "!(i.deletedAt == @p0)",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        !(i.deletedAt == 25))).Expression);

            // Bitwise
            Assert.Equal(
                "i.deletedAt ^ @p0",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        i.deletedAt ^ 3)).Expression);

            // Sumar, multiplicar y restar
            Assert.Equal(
                "(i.deletedAt * @p0 - @p1) + @p2",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        (i.deletedAt * 5) - 5 + 6)).Expression);

            // Módulo
            Assert.Equal(
                "i.deletedAt % @p0",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        i.deletedAt % 5)).Expression);

            string[] testList = new string[] { "op1", "op2" };

            // This expression is fully calculable at compile time, and
            // should reduce to a constant expression
            Assert.Equal(
                "@p0",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        testList.ToList().Contains("op1"))).Expression);

            Assert.Equal(
                "i.deletedAt != @p0",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        i.deletedAt != null)).Expression);

            var sampleObject = new
            {
                prop1 = new
                {
                    prop2 = "My string",

                    number = 58
                }
            };

            Assert.Equal(
                "i.SABENTIS_ADDRESS.roadname.Contains(@p0)",
                expVisitor.GetExpressionText(
                    LambdaBuilder.Lambda((CORE_PERSON i) =>
                        i.SABENTIS_ADDRESS.roadname.Contains(sampleObject.prop1.prop2))).Expression);
@StefH
Copy link
Collaborator

StefH commented Nov 27, 2018

Do you know the project https://github.com/esskar/Serialize.Linq ?

This tool can also be used to serialize a linq expression, however I did never test if this one also supports dynamic lambda expressions.

@david-garcia-garcia
Copy link
Contributor Author

I do know about that project, but it generates very heavy serialized lambda expressions. I am using it in some places though.

I'll upload a repo with the library so you can take a closer look at what it does. It was mostly designed to convert in-place lambda expressions to the input required by Dynamic.Linq.Core which is a text based expression + the list of arguments.

@StefH
Copy link
Collaborator

StefH commented Nov 28, 2018

OK. I'm curious to see how this is implemented.

@david-garcia-garcia
Copy link
Contributor Author

This is it: https://github.com/david-garcia-garcia/LambdaTextExpression

I just moved it way from the project where it is embeded, would need some extra work actually make this seomthing really stand-alone with proper test coverage. Y had to comment several tests where DTO's from another project are used.

@StefH
Copy link
Collaborator

StefH commented Dec 31, 2018

Interesting. Do you need Dynamitey ?

And if you need help, I can help you converting this library into a NETStandard library and also adding some more tests if needed.

@david-garcia-garcia
Copy link
Contributor Author

Dynamitey is used to ease som reflection based operations, of course they could be implemented excusively using reflection, but that would be more teidous

@zspitz
Copy link

zspitz commented Sep 24, 2020

@david-garcia-garcia What is the status of this? As I noted in #423, I've written a library that produces various string representations of expression trees, and I would like to include something similar to what you've done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants