When I started writing dwsLinq, I never intended it to just be an integrated SQL query builder. I did that first because it was both useful and easy to implement, but that was never the end goal.
Over the last few days I’ve taken a big step towards the real goal: developing a general-purpose data querying system. I factored out all of the SQL-specific stuff into its own unit and created an interface called IQueryBuilder that responds to the various query operators to build an expression tree that can be evaluated by DWS. You create a recognizer and register it with dwsLinq, that checks the value of your FROM expression and returns an IQueryBuilder if it can create an expression for it. And once I had that working, I created a second unit with a new implementation of IQueryBuilder, for querying JSON data.
I checked it in recently, and it supports all of the query operators except JOIN (which raises a compiler error, since I couldn’t figure out how to do in any meaningful way without language support for anonymous methods) and DISTINCT (which is a no-op that raises a compiler warning). It takes a JSONVariant value (supplied by the JSON Connector language extension) as input and produces a new one as output. The INTO operator expects a JSONVariant as input and can output any type. (There’s no special to distinguish array types from single elements, like with the SQL version, because this is a lot more complicated to pull off without an enforced schema. I might change that later on.)
The JSON query system is still very rough, and very much a work in progress. It’s a lot harder to get things right than SQL, because SQL relations have a schema and JSON does not. (It’s essentially the same as the difference between ensuring type safety in a static language or a dynamic one. Getting it right in the dynamic language is a lot more work!)
The query system expects that the input value will consist of an array of objects (much like a SQL result set) and should work more or less as expected under those conditions. I’ve tried to put in cases for the various query operators to handle them, but it still needs work, and I’ll keep working on it.
But what this means is that anyone could write an IQueryBuilder implementation and their own query expression objects, to be able to run LINQ expressions against arbitrary data. This is starting to become a really interesting project…