Add support for querying with LINQ and expressions #34
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This commit introduces support for LINQ querying a table repository. Unlike the document-based one, the table repository persists entities in individual columns that can therefore be queried. The document-based repository is now a separte common base interface for both queryable and non-queryable repos.
The main usage is very similar to the built-in API, where you invoke
CreateQuery
and then perform LINQ queries over it. There are obvious restrictions on what works and doesn't, and it's documented at https://docs.microsoft.com/en-us/rest/api/storageservices/query-operators-supported-for-the-table-service.The built-in implementation for querying is deeply intertwined with the ITableEntity interface, to the point that it's effectively unsable for our purposes. No amount of trial/hacking could get over the fact that TableQuery requires the T to implement ITableEntity. Short of generating dynamic proxies (a seriously complex approach), we simply cannot use that.
Luckily, it's all OData in the end, so if you build the right URIs (including headers and signatures), you don't actually need it. That includes properly parsing the continuation token headers.
So we take a dependency on OData for the URI building capabilities, but otherwise execute the queries ourselves using plain HttpClient. The same deserialization support configured for the other operations on the repo is used, so the behavior is indistinguishable from EnumerateAsync.
An extension method
EnumerateAsync(predicate)
is also provided now, which might provide a simpler API surface for simple Where-style filtering.Finally, the "native" way of consuming these queries is
IAsyncEnumerable<T>
, but the LINQ querying works overIQueryable<T>
so there is a need to bridge the two.There is some discussion in the dotnet org about this, since EF Core provides similar capabilities, but nothing exists in the platform yet. So we provide a simple
GetAsyncEnumerator
extension method forIQueryable<T>
to bridge that gap, for use with built-inawait foreach
over the query.For tests, we just
cat
the async enumerable extensions for convenience, from https://github.com/devlooped/catbag/blob/main/System/Collections/Generic/IAsyncEnumerableExtensions.cs.Fixes #33.