generated from Avanade/avanade-template
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathCosmosDbQuery.cs
71 lines (60 loc) · 3.53 KB
/
CosmosDbQuery.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// Copyright (c) Avanade. Licensed under the MIT License. See https://github.com/Avanade/CoreEx
using CoreEx.Entities;
using CoreEx.Results;
using Microsoft.Azure.Cosmos.Linq;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace CoreEx.Cosmos
{
/// <summary>
/// Encapsulates a <b>CosmosDb</b> query enabling all select-like capabilities.
/// </summary>
/// <typeparam name="T">The resultant <see cref="Type"/>.</typeparam>
/// <typeparam name="TModel">The cosmos model <see cref="Type"/>.</typeparam>
/// <param name="container">The <see cref="CosmosDbContainer"/>.</param>
/// <param name="dbArgs">The <see cref="CosmosDbArgs"/>.</param>
/// <param name="query">A function to modify the underlying <see cref="IQueryable{T}"/>.</param>
public class CosmosDbQuery<T, TModel>(CosmosDbContainer container, CosmosDbArgs dbArgs, Func<IQueryable<TModel>, IQueryable<TModel>>? query) : CosmosDbQueryBase<T, TModel, CosmosDbQuery<T, TModel>>(container, dbArgs) where T : class, IEntityKey, new() where TModel : class, IEntityKey, new()
{
private readonly Func<IQueryable<TModel>, IQueryable<TModel>>? _query = query;
/// <summary>
/// Instantiates the <see cref="IQueryable"/>.
/// </summary>
private IQueryable<TModel> AsQueryable(bool allowSynchronousQueryExecution, bool pagingSupported)
{
if (!pagingSupported && Paging is not null)
throw new NotSupportedException("Paging is not supported when accessing AsQueryable directly; paging must be applied directly to the resulting IQueryable instance.");
IQueryable<TModel> query = Container.CosmosContainer.GetItemLinqQueryable<TModel>(allowSynchronousQueryExecution: allowSynchronousQueryExecution, requestOptions: QueryArgs.GetQueryRequestOptions());
query = _query == null ? query : _query(query);
var filter = Container.Model.GetAuthorizeFilter<TModel>();
if (filter != null)
query = filter(query);
return QueryArgs.WhereModelValid(query);
}
/// <summary>
/// Gets a pre-prepared <see cref="IQueryable"/> with filtering applied as applicable.
/// </summary>
/// <returns>The <see cref="IQueryable"/>.</returns>
/// <remarks>The <see cref="CosmosDbQueryBase{T, TModel, TSelf}.Paging"/> is not supported. The query will <i>not</i> be automatically included within an <see cref="CosmosDb.Invoker"/> execution.</remarks>
public IQueryable<TModel> AsQueryable() => AsQueryable(true, false);
/// <inheritdoc/>
public override Task<Result> SelectQueryWithResultAsync<TColl>(TColl coll, CancellationToken cancellationToken = default) => Container.CosmosDb.Invoker.InvokeAsync(Container.CosmosDb, coll, async (_, items, ct) =>
{
var q = AsQueryable(false, true);
using var iterator = q.WithPaging(Paging).ToFeedIterator();
while (iterator.HasMoreResults)
{
foreach (var item in await iterator.ReadNextAsync(ct).ConfigureAwait(false))
{
if (item is not null)
items.Add(Container.MapToValue<T, TModel>(item, QueryArgs)!);
}
}
if (Paging != null && Paging.IsGetCount)
Paging.TotalCount = (await q.CountAsync(cancellationToken).ConfigureAwait(false)).Resource;
return Result.Success;
}, cancellationToken, nameof(SelectQueryWithResultAsync));
}
}