GithubHelp home page GithubHelp logo

expressionpowertools's Introduction

ExpressionPowerTools

.NET Core .NET Core Tests Generate and Publish Documentation Pack and Publish NuGet

Skip ahead to documentation

What Expression Power Tools does

Expression Power Tools is an experiment I created to better understand and more easily work with expressions. The project started with a vision: the goal to be able to write a query on a client (like Blazor WebAssembly) and execute it remotely but securely on the server, like this:

var list = await DbClientContext<ThingContext>.Query(context => context.Things)
    .Where(t => t.IsActive == ActiveFlag &&
        EF.Functions.Like(t.Name, $"%{nameFilter}%"))
    .OrderBy(t => EF.Property<DateTime>(t, nameof(Thing.Created)))
    .ExecuteRemote()
    .ToListAsync();

You can learn more about the implementation of this in the Blazor Web Assembly quickstart.

The central feature of the Core library is a set of extensions for working with queries and expressions. For example, the following code uses an extension to create the ConstantExpression parameters for the BinaryExpression then uses IExpressionEnumerable to display the expression tree:

var expr = Expression.GreaterThan(
    Expression.Constant(40),
    Expression.Constant(2));
var tree = expr.AsEnumerable(); // casts to IExpressionEnumerable
var treeDisplay = tree.ToString();

The example sets treeDisplay to:

[LogicalBinaryExpression:GreaterThan] : Boolean => (40 > 2)
  [ConstantExpression:Constant] : Int32 => 40
  [ConstantExpression:Constant] : Int32 => 2

See the Jupyter notebook example

A more involved example uses queries. Here is a query and its tree display:

var query = querySource
    .Where(e => e.Id.StartsWith("a"))
    .Select(e => new { CapturedId = e.Id })
    .OrderBy(anonType => anonType.CapturedId)
    .Take(5);

var tree = query.AsEnumerableExpression();

Calling tree.ToString() will result in:

[MethodCallExpression2:Call] : IQueryable`1 => System.Collections.Generic.List`1[Submission#8+Example].Where(e => e.Id.StartsWith("a")).Select(e => new <>f__AnonymousType0#1`1(CapturedId = e.Id)).OrderBy(anonType => anonType.CapturedId).Take(5)
  [MethodCallExpression2:Call] : IOrderedQueryable`1 => System.Collections.Generic.List`1[Submission#8+Example].Where(e => e.Id.StartsWith("a")).Select(e => new <>f__AnonymousType0#1`1(CapturedId = e.Id)).OrderBy(anonType => anonType.CapturedId)
    [MethodCallExpression2:Call] : IQueryable`1 => System.Collections.Generic.List`1[Submission#8+Example].Where(e => e.Id.StartsWith("a")).Select(e => new <>f__AnonymousType0#1`1(CapturedId = e.Id))
      [MethodCallExpression2:Call] : IQueryable`1 => System.Collections.Generic.List`1[Submission#8+Example].Where(e => e.Id.StartsWith("a"))
        [ConstantExpression:Constant] : EnumerableQuery`1 => System.Collections.Generic.List`1[Submission#8+Example]
        [UnaryExpression:Quote] : Expression`1 => e => e.Id.StartsWith("a")
          [Expression1`1:Lambda] : Func`2 => e => e.Id.StartsWith("a")
            [TypedParameterExpression:Parameter] : Example => e
            [InstanceMethodCallExpression1:Call] : Boolean => e.Id.StartsWith("a")
              [PropertyExpression:MemberAccess] : String => e.Id
                [TypedParameterExpression:Parameter] : Example => e
              [ConstantExpression:Constant] : String => "a"
      [UnaryExpression:Quote] : Expression`1 => e => new <>f__AnonymousType0#1`1(CapturedId = e.Id)
        [Expression1`1:Lambda] : Func`2 => e => new <>f__AnonymousType0#1`1(CapturedId = e.Id)
          [TypedParameterExpression:Parameter] : Example => e
          [NewExpression:New] : <>f__AnonymousType0#1`1 => new <>f__AnonymousType0#1`1(CapturedId = e.Id)
            [PropertyExpression:MemberAccess] : String => e.Id
              [TypedParameterExpression:Parameter] : Example => e
    [UnaryExpression:Quote] : Expression`1 => anonType => anonType.CapturedId
      [Expression1`1:Lambda] : Func`2 => anonType => anonType.CapturedId
        [TypedParameterExpression:Parameter] : <>f__AnonymousType0#1`1 => anonType
        [PropertyExpression:MemberAccess] : String => anonType.CapturedId
          [TypedParameterExpression:Parameter] : <>f__AnonymousType0#1`1 => anonType
  [ConstantExpression:Constant] : Int32 => 5

To get the "Take" value (results in take with value of 5):

var take = tree.MethodsWithName(nameof(Queryable.Take))
    .SelectMany(m => m.AsEnumerable().ConstantsOfType<int>())
    .First().Value; // 5

You can inspect branches of the expression tree:

var skip = query.HasFragment(q => q.Skip(5)); // false
var take5 = query.HasFragment(q => q.Take(5)); // true
var take10 = query.HasFragment(q => q.Take(10)); // false

And even make comparisons:

var query1 = querySource
    .Where(e => e.Id.StartsWith("a"))
    .Select(e => new { CapturedId = e.Id })
    .OrderBy(anonType => anonType.CapturedId)
    .Take(6);

var query2 = querySource
    .Where(e => e.Id.StartsWith("b"))
    .Select(e => new { CapturedId = e.Id })
    .OrderBy(anonType => anonType.CapturedId)
    .Take(5);

var query3 = querySource
    .Where(e => e.Id.StartsWith("a"))
    .Select(e => new { CapturedId = e.Id })
    .OrderBy(anonType => anonType.CapturedId)
    .Take(5);

var query1eq = query1.IsEquivalentTo(query); // false: Take(6) != Take(5)
var query2eq = query2.IsEquivalentTo(query); // false: StartsWith("b") != StartsWith("a")
var query3eq = query3.IsEquivalentTo(query); // true

See these examples in a Jupyter notebook

There are many more features so be sure to check out the documentation!

Documentation

There are a few options for documentation, including:

Documentation Tip Because the documentation is stored in this repo, you can use the GitHub "Go to file" feature to quickly find documentation for a type or member. Just click Go to File and type the name of the method or type and look for the markdown file. You can infer the type of documentation from the extension:

  • .a.md - assemblies
  • .ns.md - namespaces
  • .cs.md - types (classes)
  • .i.md - types (interfaces)
  • .ctor.md - constructors
  • .m.md - methods
  • .prop.md - properties

Libraries

The following libraries are available to use.

Core

NuGet Badge Tests Coverage

Install-Package ExpressionPowerTools.Core -Version 0.9.4-alpha

Power tools for working with IQueryable and Expression trees. Enables enumeration of the tree, comparisons ("similar" and "equivalent") and interception to take snapshots and/or mutate expressions.

API Documentation

Serialization

NuGet Badge Tests Coverage

Install-Package ExpressionPowerTools.Serialization -Version 0.9.4-alpha

Power tools for writing client-side queries that can be safely serialized to run on the server.

API Documentation

ASP.NET Core Middleware for EF Core

NuGet Badge Tests Coverage

Install-Package ExpressionPowerTools.Serialization.EFCore.AspNetCore -Version 0.9.4-alpha

Power tools for deserializing queries initiated by remote clients.

API Documentation

Http Client

NuGet Badge Tests Coverage

Install-Package ExpressionPowerTools.Serialization.EFCore.Http -Version 0.9.4-alpha

Power tools for running remote queries over HTTP, for example a Blazor WebAssembly client.

API Documentation

Documentation Generator

The documentation generator is an internal utility that auto-generates API documentation based on comments and reflection. IT directly generates markdown. Also self-documents.

API Documentation

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.