Skip to content
This repository has been archived by the owner on Jul 12, 2020. It is now read-only.

Commit

Permalink
Single response methods now automatically set MaxItemCount to 1. Addr…
Browse files Browse the repository at this point in the history
…esses issue #44
  • Loading branch information
Elfocrash committed Dec 2, 2018
1 parent fd99bc3 commit 6b7a225
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 15 deletions.
2 changes: 1 addition & 1 deletion samples/Cosmonaut.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ static async Task Main(string[] args)

var aCarId = addedCars.SuccessfulEntities.First().Entity.Id;

var firstAddedCar = await carStore.QueryMultipleAsync("select * from c where c.id = @id", new { id = aCarId });
var firstAddedCar = await carStore.Query().FirstOrDefaultAsync();
var allTheCars = await carStore.QueryMultipleAsync<Car>("select * from c");

var carPageOne = await carStore.Query("select * from c order by c.Name asc").WithPagination(1, 5).ToPagedListAsync();
Expand Down
1 change: 0 additions & 1 deletion samples/Cosmonaut.Shared/SharedEntity.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Cosmonaut.Attributes;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

namespace Cosmonaut.Shared
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,4 @@ public CosmosStoreTriggerAttribute(string databaseName, string overridenCollecti
/// </example>
public string PreferredLocations { get; set; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using Cosmonaut.Extensions;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.ChangeFeedProcessor;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.WebJobs.Host.Bindings;
using Microsoft.Azure.WebJobs.Host.Listeners;
using Microsoft.Azure.WebJobs.Host.Protocols;
Expand Down
17 changes: 16 additions & 1 deletion src/Cosmonaut/Extensions/CosmosResultExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ public static class CosmosResultExtensions
private static async Task<List<T>> GetSingleOrFirstFromQueryable<T>(IQueryable<T> queryable,
CancellationToken cancellationToken)
{
var feedOptions = queryable.GetFeedOptionsForQueryable();
SetFeedOptionsForSingleOperation(ref queryable, out var feedOptions);

if (feedOptions?.RequestContinuation == null)
{
return await GetResultsFromQueryToList(queryable, true, cancellationToken);
Expand All @@ -146,6 +147,20 @@ public static class CosmosResultExtensions
return await GetPaginatedResultsFromQueryable(queryable, cancellationToken, feedOptions);
}

private static void SetFeedOptionsForSingleOperation<T>(ref IQueryable<T> queryable, out FeedOptions feedOptions)
{
feedOptions = queryable.GetFeedOptionsForQueryable();
if (feedOptions != null)
{
feedOptions.MaxItemCount = 1;
queryable.SetFeedOptionsForQueryable(feedOptions);
return;
}

feedOptions = new FeedOptions {MaxItemCount = 1};
queryable.SetFeedOptionsForQueryable(feedOptions);
}

private static async Task<CosmosPagedResults<T>> GetPagedListFromQueryable<T>(IQueryable<T> queryable,
CancellationToken cancellationToken)
{
Expand Down
10 changes: 4 additions & 6 deletions src/Cosmonaut/Extensions/PaginationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using System.Reflection;
using Cosmonaut.Internal;
using Microsoft.Azure.Documents.Client;

namespace Cosmonaut.Extensions
Expand Down Expand Up @@ -67,19 +68,16 @@ internal static FeedOptions GetFeedOptionsForQueryable<T>(this IQueryable<T> que
if (!queryable.GetType().Name.Equals("DocumentQuery`1"))
return null;

return (FeedOptions)queryable.Provider.GetType().GetTypeInfo().GetField("feedOptions", BindingFlags.Instance | BindingFlags.NonPublic)
.GetValue(queryable.Provider);
return (FeedOptions) InternalTypeCache.Instance.FeedOptionsFieldInfo.GetValue(queryable.Provider);
}

internal static void SetFeedOptionsForQueryable<T>(this IQueryable<T> queryable, FeedOptions feedOptions)
{
if (!queryable.GetType().Name.Equals("DocumentQuery`1"))
return;

queryable.GetType().GetTypeInfo().GetField("feedOptions", BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(queryable, feedOptions);
queryable.Provider.GetType().GetTypeInfo().GetField("feedOptions", BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(queryable.Provider, feedOptions);
InternalTypeCache.Instance.GetFieldInfoFromCache(queryable.GetType(), "feedOptions", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(queryable, feedOptions);
InternalTypeCache.Instance.FeedOptionsFieldInfo.SetValue(queryable.Provider, feedOptions);
}
}
}
31 changes: 29 additions & 2 deletions src/Cosmonaut/Internal/InternalTypeCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,32 @@ internal ConstructorInfo FeedResponseCtorInfo<T>() => Type.GetType($"Microsoft.A

internal FieldInfo DocumentFeedOrDbLinkFieldInfo { get; }

internal FieldInfo FeedOptionsFieldInfo { get; }

private ConcurrentDictionary<string, PropertyInfo[]> PropertyCache { get; } = new ConcurrentDictionary<string, PropertyInfo[]>();

private ConcurrentDictionary<Tuple<string, string>, FieldInfo> FieldInfoCache { get; } = new ConcurrentDictionary<Tuple<string, string>, FieldInfo>();

internal FieldInfo GetFieldInfoFromCache(Type type, string fieldName, BindingFlags bindingFlags)
{
var entityName = type.AssemblyQualifiedName;

var key = new Tuple<string, string>(entityName, fieldName);
if (FieldInfoCache.ContainsKey(key))
{
FieldInfoCache.TryGetValue(key, out var field);
return field;
}

var fieldInfo = type.GetTypeInfo().GetField(fieldName, bindingFlags);

if (IsAnonymousType(type))
return fieldInfo;

FieldInfoCache.TryAdd(key, fieldInfo);
return fieldInfo;
}

internal PropertyInfo[] GetPropertiesFromCache(Type type)
{
if(type == null)
Expand Down Expand Up @@ -48,8 +72,11 @@ private InternalTypeCache()
DocumentServiceResponseCtorInfo = Type.GetType($"Microsoft.Azure.Documents.DocumentServiceResponse{LibVersion}")
.GetTypeInfo().GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];
DictionaryNameValueCollectionType = Type.GetType($"Microsoft.Azure.Documents.Collections.DictionaryNameValueCollection{LibVersion}");
DocumentFeedOrDbLinkFieldInfo = Type.GetType($"Microsoft.Azure.Documents.Linq.DocumentQueryProvider{LibVersion}").GetTypeInfo()
.GetField("documentsFeedOrDatabaseLink", BindingFlags.Instance | BindingFlags.NonPublic);

var documentQueryProviderTypeInfo = Type.GetType($"Microsoft.Azure.Documents.Linq.DocumentQueryProvider{LibVersion}").GetTypeInfo();

DocumentFeedOrDbLinkFieldInfo = documentQueryProviderTypeInfo.GetField("documentsFeedOrDatabaseLink", BindingFlags.Instance | BindingFlags.NonPublic);
FeedOptionsFieldInfo = documentQueryProviderTypeInfo.GetField("feedOptions", BindingFlags.Instance | BindingFlags.NonPublic);
}

internal static InternalTypeCache Instance
Expand Down
1 change: 0 additions & 1 deletion tests/Cosmonaut.System/CosmonautClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using Cosmonaut.Extensions;
using Cosmonaut.Response;
using Cosmonaut.System.Models;
using Cosmonaut.Testing;
using FluentAssertions;
using FluentAssertions.Equivalency;
using Microsoft.Azure.Documents;
Expand Down
23 changes: 23 additions & 0 deletions tests/Cosmonaut.System/CosmosStoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,29 @@ public async Task WhenValidEntitiesAreAdded_ThenTheyCanBeFoundAsync()
alpacaFound.Should().BeEquivalentTo(JsonConvert.DeserializeObject<Alpaca>(addedAlpacas.SuccessfulEntities.Single().ResourceResponse.Resource.ToString()));
}

[Fact]
public async Task WhenValidSingleEntitiesAreAdded_ThenTheyCanBeFoundAsSinglesAsync()
{
var catStore = _serviceProvider.GetService<ICosmosStore<Cat>>();
var dogStore = _serviceProvider.GetService<ICosmosStore<Dog>>();
var lionStore = _serviceProvider.GetService<ICosmosStore<Lion>>();
var birdStore = _serviceProvider.GetService<ICosmosStore<Bird>>();
var addedCats = await ExecuteMultipleAddOperationsForType<Cat>(list => catStore.AddRangeAsync(list), 1);
var addedDogs = await ExecuteMultipleAddOperationsForType<Dog>(list => dogStore.AddRangeAsync(list), 1);
var addedLions = await ExecuteMultipleAddOperationsForType<Lion>(list => lionStore.AddRangeAsync(list), 1);
var addedBirds = await ExecuteMultipleAddOperationsForType<Bird>(list => birdStore.AddRangeAsync(list), 1);

var catFound = await catStore.Query().FirstAsync();
var dogFound = await dogStore.Query().FirstOrDefaultAsync();
var lionFound = await lionStore.Query().SingleAsync();
var birdFound = await birdStore.Query(new FeedOptions{MaxItemCount = 100}).SingleOrDefaultAsync();

catFound.Should().BeEquivalentTo(JsonConvert.DeserializeObject<Cat>(addedCats.SuccessfulEntities.Single().ResourceResponse.Resource.ToString()));
dogFound.Should().BeEquivalentTo(JsonConvert.DeserializeObject<Dog>(addedDogs.SuccessfulEntities.Single().ResourceResponse.Resource.ToString()));
lionFound.Should().BeEquivalentTo(JsonConvert.DeserializeObject<Lion>(addedLions.SuccessfulEntities.Single().ResourceResponse.Resource.ToString()));
birdFound.Should().BeEquivalentTo(JsonConvert.DeserializeObject<Bird>(addedBirds.SuccessfulEntities.Single().ResourceResponse.Resource.ToString()));
}

[Fact]
public async Task WhenValidEntitiesAreNotAdded_ThenTheyCanNotBeFoundAsync()
{
Expand Down

0 comments on commit 6b7a225

Please sign in to comment.