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 #33

Closed
kzu opened this issue Jun 15, 2021 · 0 comments · Fixed by #34
Closed

Add support for querying #33

kzu opened this issue Jun 15, 2021 · 0 comments · Fixed by #34
Labels
enhancement New feature or request

Comments

@kzu
Copy link
Member

kzu commented Jun 15, 2021

There is fairly capable querying capability for the table storage service. We should provide something similar (mostly identical?) to the LINQ support to be competitive, while still preserving the POCO-ness of our abstractions.

The goal is to support the following syntax:

await foreach (var info in from book in repo.CreateQuery()
                           where book.Author == "Rick Riordan" && book.Format == "Hardback" && book.IsPublished
                           select new { book.ISBN, book.Title })
{
  Console.WriteLine($"Found {info.Title} by Rick Riordan (ISBN: {info.ISBN}).");
}

Back this issue
Back this issue

@kzu kzu added the enhancement New feature or request label Jun 15, 2021
kzu added a commit that referenced this issue 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<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 added a commit that referenced this issue 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<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 added a commit that referenced this issue 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<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 closed this as completed in #34 Jun 15, 2021
kzu added a commit that referenced this issue 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<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.
@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
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant