Skip to content

Commit

Permalink
Fixed a bug with read feed with partition key. (#612)
Browse files Browse the repository at this point in the history
* Fixed a bug with read feed with partition key. Added additional tests for this scenario.

* Additional linq tests

* Fixing a coding convention

* ChangeLog included

* Fixing test
  • Loading branch information
j82w authored and kirankumarkolli committed Aug 1, 2019
1 parent 5c1315a commit d2bd043
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 30 deletions.
8 changes: 6 additions & 2 deletions Microsoft.Azure.Cosmos/src/Handler/RequestMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,13 @@ public virtual Stream Content

internal bool IsPropertiesInitialized => this.properties.IsValueCreated;

internal bool IsPartitionedFeedOperation => this.OperationType == OperationType.ReadFeed &&
/// <summary>
/// The partition key range handler is only needed for read feed on partitioned resources
/// where the partition key range needs to be computed.
/// </summary>
internal bool IsPartitionKeyRangeHandlerRequired => this.OperationType == OperationType.ReadFeed &&
(this.ResourceType == ResourceType.Document || this.ResourceType == ResourceType.Conflict) &&
this.PartitionKeyRangeId == null;
this.PartitionKeyRangeId == null && this.Headers.PartitionKey == null;

/// <summary>
/// Request properties Per request context available to handlers.
Expand Down
2 changes: 1 addition & 1 deletion Microsoft.Azure.Cosmos/src/Handler/RouterHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public override Task<ResponseMessage> SendAsync(
CancellationToken cancellationToken)
{
RequestHandler targetHandler = null;
if (request.IsPartitionedFeedOperation)
if (request.IsPartitionKeyRangeHandlerRequired)
{
targetHandler = documentFeedHandler;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,17 @@ public async Task DatabaseTest(bool directMode)
List<DatabaseProperties> results = await this.ToListAsync(
client.GetDatabaseQueryStreamIterator,
client.GetDatabaseQueryIterator<DatabaseProperties>,
null);
null,
CosmosBasicQueryTests.RequestOptions);

CollectionAssert.IsSubsetOf(createdIds, results.Select(x => x.Id).ToList());

//Basic query
List<DatabaseProperties> queryResults = await this.ToListAsync(
client.GetDatabaseQueryStreamIterator,
client.GetDatabaseQueryIterator<DatabaseProperties>,
"select * from T where STARTSWITH(T.id, \"BasicQueryDb\")");
"select * from T where STARTSWITH(T.id, \"BasicQueryDb\")",
CosmosBasicQueryTests.RequestOptions);

CollectionAssert.AreEquivalent(createdIds, queryResults.Select(x => x.Id).ToList());
}
Expand Down Expand Up @@ -121,15 +123,17 @@ public async Task ContainerTest(bool directMode)
List<ContainerProperties> results = await this.ToListAsync(
database.GetContainerQueryStreamIterator,
database.GetContainerQueryIterator<ContainerProperties>,
null);
null,
CosmosBasicQueryTests.RequestOptions);

CollectionAssert.IsSubsetOf(createdIds, results.Select(x => x.Id).ToList());

//Basic query
List<ContainerProperties> queryResults = await this.ToListAsync(
database.GetContainerQueryStreamIterator,
database.GetContainerQueryIterator<ContainerProperties>,
"select * from T where STARTSWITH(T.id, \"BasicQueryContainer\")");
"select * from T where STARTSWITH(T.id, \"BasicQueryContainer\")",
CosmosBasicQueryTests.RequestOptions);

CollectionAssert.AreEquivalent(createdIds, queryResults.Select(x => x.Id).ToList());
}
Expand Down Expand Up @@ -160,7 +164,8 @@ public async Task ItemTest(bool directMode)
List<dynamic> queryResults = await this.ToListAsync(
container.GetItemQueryStreamIterator,
container.GetItemQueryIterator<dynamic>,
"select * from T where STARTSWITH(T.id, \"BasicQueryItem\")");
"select * from T where STARTSWITH(T.id, \"BasicQueryItem\")",
CosmosBasicQueryTests.RequestOptions);

if (queryResults.Count < 3)
{
Expand All @@ -178,7 +183,8 @@ public async Task ItemTest(bool directMode)
queryResults = await this.ToListAsync(
container.GetItemQueryStreamIterator,
container.GetItemQueryIterator<dynamic>,
"select * from T where STARTSWITH(T.id, \"BasicQueryItem\")");
"select * from T where STARTSWITH(T.id, \"BasicQueryItem\")",
CosmosBasicQueryTests.RequestOptions);
}

List<string> ids = queryResults.Select(x => (string)x.id).ToList();
Expand All @@ -188,10 +194,54 @@ public async Task ItemTest(bool directMode)
List<dynamic> results = await this.ToListAsync(
container.GetItemQueryStreamIterator,
container.GetItemQueryIterator<dynamic>,
null);
null,
CosmosBasicQueryTests.RequestOptions);


ids = results.Select(x => (string)x.id).ToList();
CollectionAssert.IsSubsetOf(createdIds, ids);

//Read All with partition key
results = await this.ToListAsync(
container.GetItemQueryStreamIterator,
container.GetItemQueryIterator<dynamic>,
null,
new QueryRequestOptions()
{
MaxItemCount = 1,
PartitionKey = new PartitionKey("BasicQueryItem")
});

Assert.AreEqual(1, results.Count);

//Read All with partition key
results = container.GetItemLinqQueryable<dynamic>(
allowSynchronousQueryExecution: true,
requestOptions: new QueryRequestOptions()
{
MaxItemCount = 1,
PartitionKey = new PartitionKey("BasicQueryItem")
}).ToList();

Assert.AreEqual(1, results.Count);

// LINQ to feed iterator Read All with partition key
FeedIterator<dynamic> iterator = container.GetItemLinqQueryable<dynamic>(
allowSynchronousQueryExecution: true,
requestOptions: new QueryRequestOptions()
{
MaxItemCount = 1,
PartitionKey = new PartitionKey("BasicQueryItem")
}).ToFeedIterator();

List<dynamic> linqResults = new List<dynamic>();
while (iterator.HasMoreResults)
{
linqResults.AddRange(await iterator.ReadNextAsync());
}

Assert.AreEqual(1, linqResults.Count);
Assert.AreEqual("BasicQueryItem", linqResults.First().pk.ToString());
}

[TestMethod]
Expand All @@ -213,7 +263,8 @@ public async Task ScriptsStoredProcedureTest(bool directMode)
List<StoredProcedureProperties> queryResults = await this.ToListAsync(
scripts.GetStoredProcedureQueryStreamIterator,
scripts.GetStoredProcedureQueryIterator<StoredProcedureProperties>,
"select * from T where STARTSWITH(T.id, \"BasicQuerySp\")");
"select * from T where STARTSWITH(T.id, \"BasicQuerySp\")",
CosmosBasicQueryTests.RequestOptions);

if(queryResults.Count < 3)
{
Expand All @@ -229,7 +280,8 @@ public async Task ScriptsStoredProcedureTest(bool directMode)
queryResults = await this.ToListAsync(
scripts.GetStoredProcedureQueryStreamIterator,
scripts.GetStoredProcedureQueryIterator<StoredProcedureProperties>,
"select * from T where STARTSWITH(T.id, \"BasicQuerySp\")");
"select * from T where STARTSWITH(T.id, \"BasicQuerySp\")",
CosmosBasicQueryTests.RequestOptions);
}

CollectionAssert.AreEquivalent(createdIds, queryResults.Select(x => x.Id).ToList());
Expand All @@ -238,7 +290,8 @@ public async Task ScriptsStoredProcedureTest(bool directMode)
List<StoredProcedureProperties> results = await this.ToListAsync(
scripts.GetStoredProcedureQueryStreamIterator,
scripts.GetStoredProcedureQueryIterator<StoredProcedureProperties>,
null);
null,
CosmosBasicQueryTests.RequestOptions);

CollectionAssert.IsSubsetOf(createdIds, results.Select(x => x.Id).ToList());
}
Expand All @@ -262,7 +315,8 @@ public async Task ScriptsUserDefinedFunctionTest(bool directMode)
List<UserDefinedFunctionProperties> queryResults = await this.ToListAsync(
scripts.GetUserDefinedFunctionQueryStreamIterator,
scripts.GetUserDefinedFunctionQueryIterator<UserDefinedFunctionProperties>,
"select * from T where STARTSWITH(T.id, \"BasicQueryUdf\")");
"select * from T where STARTSWITH(T.id, \"BasicQueryUdf\")",
CosmosBasicQueryTests.RequestOptions);

if (queryResults.Count < 3)
{
Expand All @@ -278,7 +332,8 @@ public async Task ScriptsUserDefinedFunctionTest(bool directMode)
queryResults = await this.ToListAsync(
scripts.GetUserDefinedFunctionQueryStreamIterator,
scripts.GetUserDefinedFunctionQueryIterator<UserDefinedFunctionProperties>,
"select * from T where STARTSWITH(T.id, \"BasicQueryUdf\")");
"select * from T where STARTSWITH(T.id, \"BasicQueryUdf\")",
CosmosBasicQueryTests.RequestOptions);
}

CollectionAssert.AreEquivalent(createdIds, queryResults.Select(x => x.Id).ToList());
Expand All @@ -287,7 +342,8 @@ public async Task ScriptsUserDefinedFunctionTest(bool directMode)
List<UserDefinedFunctionProperties> results = await this.ToListAsync(
scripts.GetUserDefinedFunctionQueryStreamIterator,
scripts.GetUserDefinedFunctionQueryIterator<UserDefinedFunctionProperties>,
null);
null,
CosmosBasicQueryTests.RequestOptions);

CollectionAssert.IsSubsetOf(createdIds, results.Select(x => x.Id).ToList());
}
Expand All @@ -311,7 +367,8 @@ public async Task ScriptsTriggerTest(bool directMode)
List<TriggerProperties> queryResults = await this.ToListAsync(
scripts.GetTriggerQueryStreamIterator,
scripts.GetTriggerQueryIterator<TriggerProperties>,
"select * from T where STARTSWITH(T.id, \"BasicQueryTrigger\")");
"select * from T where STARTSWITH(T.id, \"BasicQueryTrigger\")",
CosmosBasicQueryTests.RequestOptions);

if (queryResults.Count < 3)
{
Expand All @@ -327,7 +384,8 @@ public async Task ScriptsTriggerTest(bool directMode)
queryResults = await this.ToListAsync(
scripts.GetTriggerQueryStreamIterator,
scripts.GetTriggerQueryIterator<TriggerProperties>,
"select * from T where STARTSWITH(T.id, \"BasicQueryTrigger\")");
"select * from T where STARTSWITH(T.id, \"BasicQueryTrigger\")",
CosmosBasicQueryTests.RequestOptions);
}

CollectionAssert.AreEquivalent(createdIds, queryResults.Select(x => x.Id).ToList());
Expand All @@ -336,17 +394,22 @@ public async Task ScriptsTriggerTest(bool directMode)
List<TriggerProperties> results = await this.ToListAsync(
scripts.GetTriggerQueryStreamIterator,
scripts.GetTriggerQueryIterator<TriggerProperties>,
null);
null,
CosmosBasicQueryTests.RequestOptions);

CollectionAssert.IsSubsetOf(createdIds, results.Select(x => x.Id).ToList());
}

private delegate FeedIterator<T> Query<T>(string querytext, string continuationToken, QueryRequestOptions options);
private delegate FeedIterator QueryStream(string querytext, string continuationToken, QueryRequestOptions options);

private async Task<List<T>> ToListAsync<T>(QueryStream createStreamQuery, Query<T> createQuery, string queryText)
private async Task<List<T>> ToListAsync<T>(
QueryStream createStreamQuery,
Query<T> createQuery,
string queryText,
QueryRequestOptions requestOptions)
{
FeedIterator feedStreamIterator = createStreamQuery(queryText, null, RequestOptions);
FeedIterator feedStreamIterator = createStreamQuery(queryText, null, requestOptions);
List<T> streamResults = new List<T>();
while (feedStreamIterator.HasMoreResults)
{
Expand All @@ -365,7 +428,7 @@ private async Task<List<T>> ToListAsync<T>(QueryStream createStreamQuery, Query<
List<T> pagedStreamResults = new List<T>();
do
{
FeedIterator pagedFeedIterator = createStreamQuery(queryText, continuationToken, RequestOptions);
FeedIterator pagedFeedIterator = createStreamQuery(queryText, continuationToken, requestOptions);
ResponseMessage response = await pagedFeedIterator.ReadNextAsync();
response.EnsureSuccessStatusCode();

Expand All @@ -384,7 +447,7 @@ private async Task<List<T>> ToListAsync<T>(QueryStream createStreamQuery, Query<
string streamPagedResultString = JsonConvert.SerializeObject(pagedStreamResults);
Assert.AreEqual(streamPagedResultString, streamResultString);

FeedIterator<T> feedIterator = createQuery(queryText, null, RequestOptions);
FeedIterator<T> feedIterator = createQuery(queryText, null, requestOptions);
List<T> results = new List<T>();
while (feedIterator.HasMoreResults)
{
Expand All @@ -399,7 +462,7 @@ private async Task<List<T>> ToListAsync<T>(QueryStream createStreamQuery, Query<
List<T> pagedResults = new List<T>();
do
{
FeedIterator<T> pagedFeedIterator = createQuery(queryText, continuationToken, RequestOptions);
FeedIterator<T> pagedFeedIterator = createQuery(queryText, continuationToken, requestOptions);
FeedResponse<T> iterator = await pagedFeedIterator.ReadNextAsync();
Assert.IsTrue(iterator.Count <= 1);
Assert.IsTrue(iterator.Resource.Count() <= 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public void IsFeedOperation_ForDocumentReads()
RequestMessage request = new RequestMessage();
request.OperationType = OperationType.ReadFeed;
request.ResourceType = ResourceType.Document;
Assert.IsTrue(request.IsPartitionedFeedOperation);
Assert.IsTrue(request.IsPartitionKeyRangeHandlerRequired);
}

[TestMethod]
Expand All @@ -25,7 +25,7 @@ public void IsFeedOperation_ForConflictReads()
RequestMessage request = new RequestMessage();
request.OperationType = OperationType.ReadFeed;
request.ResourceType = ResourceType.Conflict;
Assert.IsTrue(request.IsPartitionedFeedOperation);
Assert.IsTrue(request.IsPartitionKeyRangeHandlerRequired);
}

[TestMethod]
Expand All @@ -35,7 +35,7 @@ public void IsFeedOperation_ForChangeFeed()
request.OperationType = OperationType.ReadFeed;
request.ResourceType = ResourceType.Document;
request.PartitionKeyRangeId = new PartitionKeyRangeIdentity("something");
Assert.IsFalse(request.IsPartitionedFeedOperation);
Assert.IsFalse(request.IsPartitionKeyRangeHandlerRequired);
}

[TestMethod]
Expand All @@ -44,12 +44,12 @@ public void IsFeedOperation_ForOtherOperations()
RequestMessage request = new RequestMessage();
request.OperationType = OperationType.Upsert;
request.ResourceType = ResourceType.Document;
Assert.IsFalse(request.IsPartitionedFeedOperation);
Assert.IsFalse(request.IsPartitionKeyRangeHandlerRequired);

RequestMessage request2 = new RequestMessage();
request2.OperationType = OperationType.ReadFeed;
request2.ResourceType = ResourceType.Database;
Assert.IsFalse(request2.IsPartitionedFeedOperation);
Assert.IsFalse(request2.IsPartitionKeyRangeHandlerRequired);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public async Task CosmosConflictsIteratorBuildsSettings()

TestHandler testHandler = new TestHandler((request, cancellationToken) =>
{
Assert.IsTrue(request.IsPartitionedFeedOperation);
Assert.IsTrue(request.IsPartitionKeyRangeHandlerRequired);
Assert.AreEqual(OperationType.ReadFeed, request.OperationType);
Assert.AreEqual(ResourceType.Conflict, request.ResourceType);
ResponseMessage handlerResponse = TestHandler.ReturnSuccess().Result;
Expand Down
3 changes: 3 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Fixed
- [#612] (https://github.com/Azure/azure-cosmos-dotnet-v3/pull/612) Bug fix for ReadFeed with partition-key

## [3.1.0](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.1.0) - 2019-07-26

### Added
Expand Down

0 comments on commit d2bd043

Please sign in to comment.