Skip to content

Commit b5f11b8

Browse files
author
Adrian Hall
committed
(#173) Updated async methods in query.
1 parent f5777b9 commit b5f11b8

File tree

9 files changed

+126
-445
lines changed

9 files changed

+126
-445
lines changed

src/CommunityToolkit.Datasync.Server.Abstractions/Tables/IRepository.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,24 @@ public interface IRepository<TEntity> where TEntity : ITableData
6666
/// <exception cref="HttpException">Thrown if the entity creation would produce a normal HTTP error.</exception>
6767
/// <exception cref="RepositoryException">Thrown is there is an error in the repository.</exception>
6868
ValueTask ReplaceAsync(TEntity entity, byte[]? version = null, CancellationToken cancellationToken = default);
69+
70+
/// <summary>
71+
/// Executes a count against the query provided, which came from this data store. This allows you
72+
/// to override the count operation to provide a more efficient count operation.
73+
/// </summary>
74+
/// <param name="query">The queryable being counted.</param>
75+
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe.</param>
76+
/// <returns>The count of entities matching the query.</returns>
77+
ValueTask<int> CountAsync(IQueryable query, CancellationToken cancellationToken = default)
78+
=> ValueTask.FromResult(query.Cast<object>().Count());
79+
80+
/// <summary>
81+
/// Executes a query retrieval against the query provided, which came from this data store. This allows you
82+
/// to override the ToList operation to provide a more efficient operation.
83+
/// </summary>
84+
/// <param name="query">The queryable being executed.</param>
85+
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to observe.</param>
86+
/// <returns>The entities matching the query.</returns>
87+
ValueTask<List<object>> ToListAsync(IQueryable query, CancellationToken cancellationToken = default)
88+
=> ValueTask.FromResult(query.Cast<object>().ToList());
6989
}

src/CommunityToolkit.Datasync.Server.EntityFrameworkCore/EntityTableRepository.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,5 +209,23 @@ await WrapExceptionAsync(entity.Id, async () =>
209209
_ = await Context.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
210210
}, cancellationToken).ConfigureAwait(false);
211211
}
212+
213+
/// <inheritdoc />
214+
/// <remarks>
215+
/// The entity framework core edition of this method uses the async method.
216+
/// </remarks>
217+
public virtual async ValueTask<int> CountAsync(IQueryable query, CancellationToken cancellationToken = default)
218+
{
219+
return await EntityFrameworkQueryableExtensions.CountAsync(query.Cast<object>(), cancellationToken).ConfigureAwait(false);
220+
}
221+
222+
/// <inheritdoc />
223+
/// <remarks>
224+
/// The entity framework core edition of this method uses the async method.
225+
/// </remarks>
226+
public virtual async ValueTask<List<object>> ToListAsync(IQueryable query, CancellationToken cancellationToken = default)
227+
{
228+
return await EntityFrameworkQueryableExtensions.ToListAsync(query.Cast<object>(), cancellationToken).ConfigureAwait(false);
229+
}
212230
#endregion
213231
}

src/CommunityToolkit.Datasync.Server/Controllers/TableController.Query.cs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,22 +69,34 @@ public virtual async Task<IActionResult> QueryAsync(CancellationToken cancellati
6969
return BadRequest(validationException.Message);
7070
}
7171

72-
// Note that some IQueryable providers cannot execute all queries against the data source, so we have
73-
// to switch to in-memory processing for those queries. This is done by calling ToListAsync() on the
74-
// IQueryable. This is not ideal, but it is the only way to support all of the OData query options.
75-
IEnumerable<object>? results = null;
76-
await ExecuteQueryWithClientEvaluationAsync(dataset, ds =>
72+
List<object>? results = null;
73+
await ExecuteQueryWithClientEvaluationAsync(dataset, async ds =>
7774
{
78-
results = (IEnumerable<object>)queryOptions.ApplyTo(ds, querySettings);
79-
return Task.CompletedTask;
75+
IQueryable query = queryOptions.ApplyTo(ds, querySettings);
76+
// results = query.Cast<object>().ToList();
77+
results = await Repository.ToListAsync(queryOptions.ApplyTo(ds, querySettings), cancellationToken).ConfigureAwait(false);
78+
79+
// If the request results in an ISelectExpandWrapper, then $select was used and
80+
// the model will be incomplete. JSON rendering just turns this into a dictionary,
81+
// so we'll do the same here.
82+
if (results.Count > 0)
83+
{
84+
for (int i = 0; i < results.Count; i++)
85+
{
86+
if (results[i] is ISelectExpandWrapper wrapper)
87+
{
88+
results[i] = wrapper.ToDictionary();
89+
}
90+
}
91+
}
8092
});
8193

8294
int count = 0;
83-
FilterQueryOption? filter = queryOptions.Filter;
8495
await ExecuteQueryWithClientEvaluationAsync(dataset, async ds =>
8596
{
86-
IQueryable<TEntity> q = (IQueryable<TEntity>)(filter?.ApplyTo(ds, new ODataQuerySettings()) ?? ds);
87-
count = await CountAsync(q, cancellationToken);
97+
IQueryable<TEntity> q = (IQueryable<TEntity>)(queryOptions.Filter?.ApplyTo(ds, new ODataQuerySettings()) ?? ds);
98+
// count = q.Cast<object>().Count();
99+
count = await CountAsync(q, cancellationToken).ConfigureAwait(false);
88100
});
89101

90102
PagedResult result = BuildPagedResult(queryOptions, results, count);

src/CommunityToolkit.Datasync.Server/Models/DatasyncServiceOptions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using CommunityToolkit.Datasync.Server.Abstractions.Json;
6+
using CommunityToolkit.Datasync.Server.OData;
67
using System.Text.Json;
78
using System.Text.Json.Serialization;
89

tests/CommunityToolkit.Datasync.Server.EntityFrameworkCore.Test/AzureSqlEntityTableRepository_Tests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ public AzureSqlEntityTableRepository_Tests(DatabaseFixture fixture, ITestOutputH
3535

3636
protected override bool CanRunLiveTests() => !string.IsNullOrEmpty(this.connectionString);
3737

38-
protected override Task<AzureSqlEntityMovie> GetEntityAsync(string id)
39-
=> Task.FromResult(Context.Movies.AsNoTracking().SingleOrDefault(m => m.Id == id));
38+
protected override async Task<AzureSqlEntityMovie> GetEntityAsync(string id)
39+
=> await Context.Movies.AsNoTracking().SingleOrDefaultAsync(m => m.Id == id);
4040

4141
protected override Task<int> GetEntityCountAsync()
4242
=> Task.FromResult(Context.Movies.Count());

0 commit comments

Comments
 (0)