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

Add support for querying with LINQ and expressions #34

Merged
merged 1 commit into from
Jun 15, 2021
Merged

Add support for querying with LINQ and expressions #34

merged 1 commit into from
Jun 15, 2021

Conversation

kzu
Copy link
Member

@kzu kzu commented Jun 15, 2021

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 over IQueryable<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 for IQueryable<T> to bridge that gap, for use with built-in await 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.

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<T> 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 over `IQueryable<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 for `IQueryable<T>` to bridge that gap, for use with built-in `await 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.
@kzu kzu enabled auto-merge (rebase) June 15, 2021 20:23
@kzu kzu merged commit 24a669e into main Jun 15, 2021
@kzu kzu deleted the dev branch June 15, 2021 20:25
@devlooped devlooped locked and limited conversation to collaborators Oct 24, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for querying
1 participant