Skip to content

Commit

Permalink
Update.
Browse files Browse the repository at this point in the history
  • Loading branch information
adityasa committed Oct 11, 2022
1 parent badbbbd commit bcba12a
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -489,5 +489,90 @@ async Task ImplementationAsync(
Assert.IsTrue(actualPartitionKeyValues.SetEquals(args.ExpectedPartitionKeyValues));
}
}

[TestMethod]
public async Task TestGeospatial()
{
string[] inputDocs = new[]
{
@"{""id"":""documentId1"",""key"":""A"",""prop"":3,""shortArray"":[{""a"":5}]}",
@"{""id"":""documentId2"",""key"":""A"",""prop"":2,""shortArray"":[{""a"":6}]}",
@"{""id"":""documentId3"",""key"":""A"",""prop"":1,""shortArray"":[{""a"":7}]}",
@"{""id"":""documentId4"",""key"":5,""prop"":3,""shortArray"":[{""a"":5}]}",
@"{""id"":""documentId5"",""key"":5,""prop"":2,""shortArray"":[{""a"":6}]}",
@"{""id"":""documentId6"",""key"":5,""prop"":1,""shortArray"":[{""a"":7}]}",
@"{""id"":""documentId10"",""prop"":3,""shortArray"":[{""a"":5}]}",
@"{""id"":""documentId11"",""prop"":2,""shortArray"":[{""a"":6}]}",
@"{""id"":""documentId12"",""prop"":1,""shortArray"":[{""a"":7}]}",
};

string All = "documentId4,documentId5,documentId6,documentId10,documentId11,documentId12,documentId1,documentId2,documentId3";
string None = string.Empty;
var testVariations = new[]
{
new
{
Query = "SELECT c.id FROM c WHERE ST_DISTANCE({'type': 'Polygon', 'coordinates': [[[35, 10], [45, 45], [15, 40], [10, 20], [35, 10]], [[20, 30], [35, 35], [30, 20], [20, 30]]]}, {'type': 'Point', 'coordinates': [30, 10]}) > 66408.034483",
Expected = new Dictionary<Cosmos.GeospatialType, string>
{
{ Cosmos.GeospatialType.Geography, All },
{ Cosmos.GeospatialType.Geometry, None },
}
},
new
{
Query = "SELECT c.id FROM c WHERE ST_ISVALID({'type': 'Polygon', 'coordinates': [[[-1000, 1000], [1000, 1000], [1000, 4000], [-1000, 4000], [-1000, 1000]]]})",
Expected = new Dictionary<Cosmos.GeospatialType, string>
{
{ Cosmos.GeospatialType.Geography, None },
{ Cosmos.GeospatialType.Geometry, All },
}
},
new
{
Query = "SELECT * FROM c WHERE NOT ST_WITHIN({'type': 'Point', 'coordinates': [0, 40]}, {'type':'Polygon','coordinates':[[[-60,20], [70,20], [70,70], [-60,70], [-60,20]]]})",
Expected = new Dictionary<Cosmos.GeospatialType, string>
{
{ Cosmos.GeospatialType.Geography, All },
{ Cosmos.GeospatialType.Geometry, None },
}
},
};

foreach (Cosmos.GeospatialType geospatialType in new[] { Cosmos.GeospatialType.Geography, Cosmos.GeospatialType.Geometry })
{
await this.CreateIngestQueryDeleteAsync(
ConnectionModes.Direct,
CollectionTypes.MultiPartition,
inputDocs,
ImplementationAsync,
"/key",
geospatialType: geospatialType);

async Task ImplementationAsync(Container container, IReadOnlyList<CosmosObject> documents)
{
foreach (var testVariation in testVariations)
{
string expectedResult = string.Join(",", testVariation.Expected[geospatialType]);

FeedIterator<Document> resultSetIterator = container.GetItemQueryIterator<Document>(
queryText: testVariation.Query,
requestOptions: new QueryRequestOptions());

List<Document> result = new List<Document>();
while (resultSetIterator.HasMoreResults)
{
result.AddRange(await resultSetIterator.ReadNextAsync());
}

string resultDocIds = string.Join(",", result.Select(doc => doc.Id));
Assert.AreEqual(
expectedResult,
resultDocIds,
$"{Environment.NewLine}Query failed for geospatial type '{geospatialType}'{Environment.NewLine}{testVariation.Query}");
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,14 @@ private async Task<IReadOnlyList<PartitionKeyRange>> GetPartitionKeyRanges(Conta

private async Task<Container> CreateMultiPartitionContainer(
string partitionKey = "/id",
Microsoft.Azure.Cosmos.IndexingPolicy indexingPolicy = null)
Microsoft.Azure.Cosmos.IndexingPolicy indexingPolicy = null,
Cosmos.GeospatialType geospatialType = Cosmos.GeospatialType.Geography)
{
ContainerResponse containerResponse = await this.CreatePartitionedContainer(
throughput: 25000,
partitionKey: partitionKey,
indexingPolicy: indexingPolicy);
indexingPolicy: indexingPolicy,
geospatialType);

IReadOnlyList<PartitionKeyRange> ranges = await this.GetPartitionKeyRanges(containerResponse);
Assert.IsTrue(
Expand All @@ -130,12 +132,14 @@ private async Task<Container> CreateMultiPartitionContainer(

private async Task<Container> CreateSinglePartitionContainer(
string partitionKey = "/id",
Microsoft.Azure.Cosmos.IndexingPolicy indexingPolicy = null)
Microsoft.Azure.Cosmos.IndexingPolicy indexingPolicy = null,
Cosmos.GeospatialType geospatialType = Cosmos.GeospatialType.Geography)
{
ContainerResponse containerResponse = await this.CreatePartitionedContainer(
throughput: 4000,
partitionKey: partitionKey,
indexingPolicy: indexingPolicy);
indexingPolicy: indexingPolicy,
geospatialType: geospatialType);

Assert.IsNotNull(containerResponse);
Assert.AreEqual(HttpStatusCode.Created, containerResponse.StatusCode);
Expand All @@ -149,21 +153,24 @@ private async Task<Container> CreateSinglePartitionContainer(
}

private async Task<Container> CreateNonPartitionedContainerAsync(
Microsoft.Azure.Cosmos.IndexingPolicy indexingPolicy = null)
Microsoft.Azure.Cosmos.IndexingPolicy indexingPolicy = null,
Cosmos.GeospatialType geospatialType = Cosmos.GeospatialType.Geography)
{
string containerName = Guid.NewGuid().ToString() + "container";
await NonPartitionedContainerHelper.CreateNonPartitionedContainer(
this.database,
containerName,
indexingPolicy == null ? null : JsonConvert.SerializeObject(indexingPolicy));
indexingPolicy == null ? null : JsonConvert.SerializeObject(indexingPolicy),
geospatialType);

return this.database.GetContainer(containerName);
}

private async Task<ContainerResponse> CreatePartitionedContainer(
int throughput,
string partitionKey = "/id",
Microsoft.Azure.Cosmos.IndexingPolicy indexingPolicy = null)
Microsoft.Azure.Cosmos.IndexingPolicy indexingPolicy = null,
Cosmos.GeospatialType geospatialType = Cosmos.GeospatialType.Geography)
{
// Assert that database exists (race deletes are possible when used concurrently)
ResponseMessage responseMessage = await this.database.ReadStreamAsync();
Expand Down Expand Up @@ -192,7 +199,8 @@ private async Task<ContainerResponse> CreatePartitionedContainer(
{
Paths = new Collection<string> { partitionKey },
Kind = PartitionKind.Hash
}
},
GeospatialConfig = new Cosmos.GeospatialConfig(geospatialType)
},
// This throughput needs to be about half the max with multi master
// otherwise it will create about twice as many partitions.
Expand All @@ -208,50 +216,57 @@ private async Task<ContainerResponse> CreatePartitionedContainer(

private Task<(Container, IReadOnlyList<CosmosObject>)> CreateNonPartitionedContainerAndIngestDocumentsAsync(
IEnumerable<string> documents,
Cosmos.IndexingPolicy indexingPolicy = null)
Cosmos.IndexingPolicy indexingPolicy = null,
Cosmos.GeospatialType geospatialType = Cosmos.GeospatialType.Geography)
{
return this.CreateContainerAndIngestDocumentsAsync(
CollectionTypes.NonPartitioned,
documents,
partitionKey: null,
indexingPolicy: indexingPolicy);
indexingPolicy: indexingPolicy,
geospatialType: geospatialType);
}

private Task<(Container, IReadOnlyList<CosmosObject>)> CreateSinglePartitionContainerAndIngestDocumentsAsync(
IEnumerable<string> documents,
string partitionKey = "/id",
Cosmos.IndexingPolicy indexingPolicy = null)
Cosmos.IndexingPolicy indexingPolicy = null,
Cosmos.GeospatialType geospatialType = Cosmos.GeospatialType.Geography)
{
return this.CreateContainerAndIngestDocumentsAsync(
CollectionTypes.SinglePartition,
documents,
partitionKey,
indexingPolicy);
indexingPolicy,
geospatialType);
}

private Task<(Container, IReadOnlyList<CosmosObject>)> CreateMultiPartitionContainerAndIngestDocumentsAsync(
IEnumerable<string> documents,
string partitionKey = "/id",
Cosmos.IndexingPolicy indexingPolicy = null)
Cosmos.IndexingPolicy indexingPolicy = null,
Cosmos.GeospatialType geospatialType = Cosmos.GeospatialType.Geography)
{
return this.CreateContainerAndIngestDocumentsAsync(
CollectionTypes.MultiPartition,
documents,
partitionKey,
indexingPolicy);
indexingPolicy,
geospatialType);
}

private async Task<(Container, IReadOnlyList<CosmosObject>)> CreateContainerAndIngestDocumentsAsync(
CollectionTypes collectionType,
IEnumerable<string> documents,
string partitionKey = "/id",
Cosmos.IndexingPolicy indexingPolicy = null)
Cosmos.IndexingPolicy indexingPolicy = null,
Cosmos.GeospatialType geospatialType = Cosmos.GeospatialType.Geography)
{
Container container = collectionType switch
{
CollectionTypes.NonPartitioned => await this.CreateNonPartitionedContainerAsync(indexingPolicy),
CollectionTypes.SinglePartition => await this.CreateSinglePartitionContainer(partitionKey, indexingPolicy),
CollectionTypes.MultiPartition => await this.CreateMultiPartitionContainer(partitionKey, indexingPolicy),
CollectionTypes.NonPartitioned => await this.CreateNonPartitionedContainerAsync(indexingPolicy, geospatialType),
CollectionTypes.SinglePartition => await this.CreateSinglePartitionContainer(partitionKey, indexingPolicy, geospatialType),
CollectionTypes.MultiPartition => await this.CreateMultiPartitionContainer(partitionKey, indexingPolicy, geospatialType),
_ => throw new ArgumentException($"Unknown {nameof(CollectionTypes)} : {collectionType}"),
};
List<CosmosObject> insertedDocuments = new List<CosmosObject>();
Expand Down Expand Up @@ -369,7 +384,8 @@ internal Task CreateIngestQueryDeleteAsync(
Query query,
string partitionKey = "/id",
Cosmos.IndexingPolicy indexingPolicy = null,
CosmosClientFactory cosmosClientFactory = null)
CosmosClientFactory cosmosClientFactory = null,
Cosmos.GeospatialType geospatialType = Cosmos.GeospatialType.Geography)
{
Task queryWrapper(Container container, IReadOnlyList<CosmosObject> inputDocuments, object throwaway)
{
Expand All @@ -384,7 +400,8 @@ Task queryWrapper(Container container, IReadOnlyList<CosmosObject> inputDocument
null,
partitionKey,
indexingPolicy,
cosmosClientFactory);
cosmosClientFactory,
geospatialType);
}

internal Task CreateIngestQueryDeleteAsync<T>(
Expand All @@ -395,7 +412,8 @@ internal Task CreateIngestQueryDeleteAsync<T>(
T testArgs,
string partitionKey = "/id",
Cosmos.IndexingPolicy indexingPolicy = null,
CosmosClientFactory cosmosClientFactory = null)
CosmosClientFactory cosmosClientFactory = null,
Cosmos.GeospatialType geospatialType = Cosmos.GeospatialType.Geography)
{
return this.CreateIngestQueryDeleteAsync(
connectionModes,
Expand All @@ -405,7 +423,8 @@ internal Task CreateIngestQueryDeleteAsync<T>(
cosmosClientFactory ?? this.CreateDefaultCosmosClient,
testArgs,
partitionKey,
indexingPolicy);
indexingPolicy,
geospatialType);
}

/// <summary>
Expand Down Expand Up @@ -434,7 +453,8 @@ internal async Task CreateIngestQueryDeleteAsync<T>(
CosmosClientFactory cosmosClientFactory,
T testArgs,
string partitionKey = "/id",
Cosmos.IndexingPolicy indexingPolicy = null)
Cosmos.IndexingPolicy indexingPolicy = null,
Cosmos.GeospatialType geospatialType = Cosmos.GeospatialType.Geography)
{
try
{
Expand All @@ -450,15 +470,18 @@ internal async Task CreateIngestQueryDeleteAsync<T>(
{
CollectionTypes.NonPartitioned => this.CreateNonPartitionedContainerAndIngestDocumentsAsync(
documents,
indexingPolicy),
indexingPolicy,
geospatialType),
CollectionTypes.SinglePartition => this.CreateSinglePartitionContainerAndIngestDocumentsAsync(
documents,
partitionKey,
indexingPolicy),
indexingPolicy,
geospatialType),
CollectionTypes.MultiPartition => this.CreateMultiPartitionContainerAndIngestDocumentsAsync(
documents,
partitionKey,
indexingPolicy),
indexingPolicy,
geospatialType),
_ => throw new ArgumentException($"Unknown {nameof(CollectionTypes)} : {collectionType}"),
};
collectionsAndDocuments.Add(await createContainerTask);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ internal static class NonPartitionedContainerHelper
internal static async Task<ContainerInternal> CreateNonPartitionedContainer(
Cosmos.Database database,
string containerId,
string indexingPolicy = null)
string indexingPolicy = null,
Cosmos.GeospatialType geospatialType = Cosmos.GeospatialType.Geography)
{
DocumentCollection documentCollection = new DocumentCollection()
{
Expand All @@ -30,6 +31,13 @@ internal static async Task<ContainerInternal> CreateNonPartitionedContainer(
documentCollection.IndexingPolicy = JsonConvert.DeserializeObject<IndexingPolicy>(indexingPolicy);
}

documentCollection.GeospatialConfig = geospatialType switch
{
Cosmos.GeospatialType.Geography => new GeospatialConfig(GeospatialType.Geography),
Cosmos.GeospatialType.Geometry => new GeospatialConfig(GeospatialType.Geometry),
_ => throw new InvalidOperationException($"Unsupported geospatialType {geospatialType}")
};

await NonPartitionedContainerHelper.CreateNonPartitionedContainer(
database,
documentCollection);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1313,8 +1313,7 @@ public void Spatial()

// ST_WITHIN
new { Description = @"ST_WITHIN Constant Foldable", Query = @"SELECT * FROM c WHERE NOT ST_WITHIN({'type': 'Point', 'coordinates': [0, 40]}, {'type':'Polygon','coordinates':[[[-60,20], [70,20], [70,70], [-60,70], [-60,20]]]})" },
new { Description = @"ST_WITHIN", Query = @"SELECT * FROM c WHERE NOT ST_WITHIN(c.geojson,
{'type':'Polygon','coordinates':[[[-60,20], [70,20], [70,70], [-60,70], [-60,20]]]})" },
new { Description = @"ST_WITHIN", Query = @"SELECT * FROM c WHERE NOT ST_WITHIN(c.geojson, {'type':'Polygon','coordinates':[[[-60,20], [70,20], [70,70], [-60,70], [-60,20]]]})" },
};

List<QueryPlanBaselineTestInput> testVariations = variations
Expand Down

0 comments on commit bcba12a

Please sign in to comment.