I work in an enterprise environment and our front ends (client and web) don't have direct DB access, but rather talk to services over a network. Proof of concept work has started for an externally available ASP.Net web API and we were thinking of trying to use an implementation of IQueryable to be able to use OData. The problem is that the web API would be another "front-end" that accesses a service layer that is a network hop away, which means we have to write our own implementation of IQueryable.
One IQueryable implementation is what I call a RangeQueryable which would be abstract and take three generic parameters; TRaw, TData, TRange. It would be an IQueryable<TData>
var queryable = new RangeQueryableImplementation<RawData, ConvertedData, DateTime>("Created");
In the previous code line RawData is TRaw, ConvertedData is TData and DateTime is TRange.
RangeQueryable would also have two abstract methods.
public abstract IEnumerable<TRaw> GetData(TRange from, TRange to);
public abstract TData Convert(TRaw raw);
GetData would make a call to the service layer over the network and use from
and to
as parameters in the call. Convert would then convert the data into my types.
TRaw is the type that the service would return, TData is the type within the frontend and the type inside the IQueryable, and TRangeis the range type.
So this would be possible:
queryable.Where(d => d.Created < DateTime.Now && d.Created > DateTime.Now.AddDays(-5))
...or the OData equivalent.
This is where the ExpressionVisitor comes in. I need to use the ExpressionVisitor to find the From and To dates.
I've looked at some tutorials and come up with some ideas. The problem I'm having is that I have no idea how I would unit test an ExpressionVisitor. How would I create an Expression which is equivalent to what the Queryable extension methods create?
I would write each test case as having a certain expression tree as an input and (in your case) expect certain range as the output. Specifying the expression tree can be done in multiple ways: - You can create the expression tree manually through calls to Expression.Call and so on (each type of expression node has a static method on the Expression type which creates it). - You can create the expression tree using the extension methods as you did above - You can use query comprehension to create the expression tree (the select from where syntax)
Each of these will end up with an expression tree. The extension methods end up calling the Expression. method as well. Most of them are in fact just inject a Call expression into the tree to themselves - you can take a look in disassembler or in the publicly available source code in the debugger.
The query comprehension syntax is just another way to write the call to the extension method, so you end up with the same thing as well.
In unit tests you don't even have to run the queryable, so just creating it, applying an expression tree to it, and running the expression visitor should be enough.