I\'ve been following the official documentation here: https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-get-started#Query
But I can\'t figure out how to correctly
If your application follows a layered architecture and you'd like to give your domain layer full control over the query then it's possible to wrap cosmos IQueryable
with a custom IQueryProvider
that implements IAsyncEnumerable
e.g.
By doing that you can hide the implementation details of asynchronously iterating over the result from your domain layer.
Persistence layer
public class PersonRepository
{
public IQueryable Persons => _cosmosContainer.GetItemLinqQueryable().ToCosmosAsyncQueryable();
}
Domain layer
var persons = await _personRepository.Persons
.Where(p => p.Name == "Name")
.AsAsyncQueryable()
.ToListAsync(cancellationToken);
ToListAsync
is available from System.Linq.Async
that can be referenced from your domain layerDomain layer extensions
public static IAsyncEnumerable AsAsyncQueryable(this IQueryable queryable)
{
return (IAsyncEnumerable)queryable;
}
Persistence layer extensions
internal static class CosmosAsyncQueryableExtensions
{
internal static IQueryable ToCosmosAsyncQueryable(this IOrderedQueryable source)
{
return new CosmosAsyncQueryable(source);
}
}
internal class CosmosAsyncQueryable : IEnumerable, IQueryable, IAsyncEnumerable
{
private readonly IQueryable _queryable;
public CosmosAsyncQueryable(IQueryable queryable)
{
_queryable = queryable;
Provider = new CosmosAsyncQueryableProvider(queryable.Provider);
}
public Type ElementType => typeof(TResult);
public Expression Expression => _queryable.Expression;
public IQueryProvider Provider { get; }
public IEnumerator GetEnumerator() => _queryable.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _queryable.GetEnumerator();
public async IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
var iterator = _queryable.ToFeedIterator();
while (iterator.HasMoreResults)
{
foreach (var item in await iterator.ReadNextAsync(cancellationToken))
{
yield return item;
}
}
}
}
internal class CosmosAsyncQueryableProvider : IQueryProvider
{
private readonly IQueryProvider _provider;
public CosmosAsyncQueryableProvider(IQueryProvider provider) => _provider = provider;
public IQueryable CreateQuery(Expression expression) =>
new CosmosAsyncQueryable(_provider.CreateQuery(expression));
public IQueryable CreateQuery(Expression expression) => CreateQuery