public async Task ContainerContractTest() { ClientEncryptionIncludedPath clientEncryptionIncludedPath1 = new ClientEncryptionIncludedPath() { Path = "/path", ClientEncryptionKeyId = "dekId", EncryptionAlgorithm = "AEAD_AES_256_CBC_HMAC_SHA256", EncryptionType = "Randomized" }; Collection <ClientEncryptionIncludedPath> paths = new Collection <ClientEncryptionIncludedPath>() { clientEncryptionIncludedPath1 }; ContainerProperties containerProperties = new ContainerProperties(Guid.NewGuid().ToString(), "/users") { IndexingPolicy = new IndexingPolicy() { Automatic = true, IndexingMode = IndexingMode.Consistent, IncludedPaths = new Collection <IncludedPath>() { new IncludedPath() { Path = "/*" } }, ExcludedPaths = new Collection <ExcludedPath>() { new ExcludedPath() { Path = "/test/*" } }, CompositeIndexes = new Collection <Collection <CompositePath> >() { new Collection <CompositePath>() { new CompositePath() { Path = "/address/city", Order = CompositePathSortOrder.Ascending }, new CompositePath() { Path = "/address/zipcode", Order = CompositePathSortOrder.Descending } } }, SpatialIndexes = new Collection <SpatialPath>() { new SpatialPath() { Path = "/address/spatial/*", SpatialTypes = new Collection <SpatialType>() { SpatialType.LineString } } } }, ClientEncryptionPolicy = new ClientEncryptionPolicy(paths) }; CosmosJsonDotNetSerializer serializer = new CosmosJsonDotNetSerializer(); Stream stream = serializer.ToStream(containerProperties); ContainerProperties deserialziedTest = serializer.FromStream <ContainerProperties>(stream); ContainerResponse response = await this.database.CreateContainerAsync(containerProperties); Assert.IsNotNull(response); Assert.IsTrue(response.RequestCharge > 0); Assert.IsNotNull(response.Headers); Assert.IsNotNull(response.Headers.ActivityId); ContainerProperties responseProperties = response.Resource; Assert.IsNotNull(responseProperties.Id); Assert.IsNotNull(responseProperties.ResourceId); Assert.IsNotNull(responseProperties.ETag); Assert.IsTrue(responseProperties.LastModified.HasValue); Assert.IsTrue(responseProperties.LastModified.Value > new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), responseProperties.LastModified.Value.ToString()); Assert.AreEqual(1, responseProperties.IndexingPolicy.IncludedPaths.Count); IncludedPath includedPath = responseProperties.IndexingPolicy.IncludedPaths.First(); Assert.AreEqual("/*", includedPath.Path); Assert.AreEqual("/test/*", responseProperties.IndexingPolicy.ExcludedPaths.First().Path); Assert.AreEqual(1, responseProperties.IndexingPolicy.CompositeIndexes.Count); Assert.AreEqual(2, responseProperties.IndexingPolicy.CompositeIndexes.First().Count); CompositePath compositePath = responseProperties.IndexingPolicy.CompositeIndexes.First().First(); Assert.AreEqual("/address/city", compositePath.Path); Assert.AreEqual(CompositePathSortOrder.Ascending, compositePath.Order); Assert.AreEqual(1, responseProperties.IndexingPolicy.SpatialIndexes.Count); SpatialPath spatialPath = responseProperties.IndexingPolicy.SpatialIndexes.First(); Assert.AreEqual("/address/spatial/*", spatialPath.Path); Assert.AreEqual(4, spatialPath.SpatialTypes.Count); // All SpatialTypes are returned Assert.AreEqual(1, responseProperties.ClientEncryptionPolicy.IncludedPaths.Count()); Assert.AreEqual(1, responseProperties.ClientEncryptionPolicy.PolicyFormatVersion); ClientEncryptionIncludedPath clientEncryptionIncludedPath = responseProperties.ClientEncryptionPolicy.IncludedPaths.First(); Assert.IsTrue(this.VerifyClientEncryptionIncludedPath(clientEncryptionIncludedPath1, clientEncryptionIncludedPath)); }
private async Task TestGloballyUniqueFieldForPartitionedCollectionHelperAsync(CosmosClient client) { ContainerProperties collectionSpec = new ContainerProperties { Id = "TestGloballyUniqueFieldForPartitionedCollection_" + Guid.NewGuid(), PartitionKeyPath = defaultPartitionKeyDefinition, UniqueKeyPolicy = new UniqueKeyPolicy { UniqueKeys = new Collection <UniqueKey> { new UniqueKey { Paths = new Collection <string> { "/name" } } } }, IndexingPolicy = new IndexingPolicy { IndexingMode = IndexingMode.Consistent, IncludedPaths = new Collection <IncludedPath> { new IncludedPath { Path = "/name/?", Indexes = new Collection <Index> { new HashIndex(DataType.String, 7) } }, }, ExcludedPaths = new Collection <ExcludedPath> { new ExcludedPath { Path = "/*" } } } }; Container collection = await this.database.CreateContainerAsync( collectionSpec, 20000); const int partitionCount = 50; List <string> partitionKeyValues = new List <string>(); for (int i = 0; i < partitionCount * 3; ++i) { partitionKeyValues.Add(Guid.NewGuid().ToString()); } string documentTemplate = "{{ \"id\":\"{0}\", \"pk\":\"{1}\", \"name\":\"{2}\" }}"; foreach (string partitionKey in partitionKeyValues) { string document = string.Format(documentTemplate, Guid.NewGuid().ToString(), partitionKey, "Same Name"); await collection.CreateItemAsync <dynamic>(JObject.Parse(document)); } string conflictDocument = string.Format(documentTemplate, Guid.NewGuid().ToString(), partitionKeyValues[0], "Same Name"); try { await collection.CreateItemAsync <dynamic>(JObject.Parse(conflictDocument)); Assert.Fail("Did not throw due to unique constraint"); } catch (CosmosException ex) { Assert.AreEqual(HttpStatusCode.Conflict, ex.StatusCode, $"Expected:Conflict, Actual:{ex.StatusCode}; Exception:ex.ToString()"); } }
private async Task <Tuple <DocumentFeedResponse <CosmosElement>, string> > ExecuteOnceAsync( IDocumentClientRetryPolicy retryPolicyInstance, CancellationToken cancellationToken) { // Don't reuse request, as the rest of client SDK doesn't reuse requests between retries. // The code leaves some temporary garbage in request (in RequestContext etc.), // which shold be erased during retries. using (DocumentServiceRequest request = await this.CreateRequestAsync()) { DocumentFeedResponse <CosmosElement> feedRespose; string partitionIdentifier; // We need to determine how to execute the request: if (LogicalPartitionKeyProvided(request)) { feedRespose = await this.ExecuteRequestAsync(request, retryPolicyInstance, cancellationToken); partitionIdentifier = $"PKId({request.Headers[HttpConstants.HttpHeaders.PartitionKey]})"; } else if (PhysicalPartitionKeyRangeIdProvided(this)) { CollectionCache collectionCache = await this.Client.GetCollectionCacheAsync(); ContainerProperties collection = await collectionCache.ResolveCollectionAsync(request, CancellationToken.None, NoOpTrace.Singleton); request.RouteTo(new PartitionKeyRangeIdentity(collection.ResourceId, base.PartitionKeyRangeId)); feedRespose = await this.ExecuteRequestAsync(request, retryPolicyInstance, cancellationToken); partitionIdentifier = base.PartitionKeyRangeId; } else { // The query is going to become a full fan out, but we go one partition at a time. if (ServiceInteropAvailable()) { // Get the routing map provider CollectionCache collectionCache = await this.Client.GetCollectionCacheAsync(); ContainerProperties collection = await collectionCache.ResolveCollectionAsync(request, CancellationToken.None, NoOpTrace.Singleton); QueryPartitionProvider queryPartitionProvider = await this.Client.GetQueryPartitionProviderAsync(); IRoutingMapProvider routingMapProvider = await this.Client.GetRoutingMapProviderAsync(); // Figure out what partition you are going to based on the range from the continuation token // If token is null then just start at partitionKeyRangeId "0" List <CompositeContinuationToken> suppliedTokens; Range <string> rangeFromContinuationToken = this.partitionRoutingHelper.ExtractPartitionKeyRangeFromContinuationToken( request.Headers, out suppliedTokens); Tuple <PartitionRoutingHelper.ResolvedRangeInfo, IReadOnlyList <Range <string> > > queryRoutingInfo = await this.TryGetTargetPartitionKeyRangeAsync( request, collection, queryPartitionProvider, routingMapProvider, rangeFromContinuationToken, suppliedTokens); if (request.IsNameBased && queryRoutingInfo == null) { request.ForceNameCacheRefresh = true; collection = await collectionCache.ResolveCollectionAsync(request, CancellationToken.None, NoOpTrace.Singleton); queryRoutingInfo = await this.TryGetTargetPartitionKeyRangeAsync( request, collection, queryPartitionProvider, routingMapProvider, rangeFromContinuationToken, suppliedTokens); } if (queryRoutingInfo == null) { throw new NotFoundException($"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}: Was not able to get queryRoutingInfo even after resolve collection async with force name cache refresh to the following collectionRid: {collection.ResourceId} with the supplied tokens: {JsonConvert.SerializeObject(suppliedTokens)}"); } request.RouteTo(new PartitionKeyRangeIdentity(collection.ResourceId, queryRoutingInfo.Item1.ResolvedRange.Id)); DocumentFeedResponse <CosmosElement> response = await this.ExecuteRequestAsync(request, retryPolicyInstance, cancellationToken); // Form a composite continuation token (range + backend continuation token). // If the backend continuation token was null for the range, // then use the next adjacent range. // This is how the default execution context serially visits every partition. if (!await this.partitionRoutingHelper.TryAddPartitionKeyRangeToContinuationTokenAsync( response.Headers, providedPartitionKeyRanges: queryRoutingInfo.Item2, routingMapProvider: routingMapProvider, collectionRid: collection.ResourceId, resolvedRangeInfo: queryRoutingInfo.Item1, trace: NoOpTrace.Singleton)) { // Collection to which this request was resolved doesn't exist. // Retry policy will refresh the cache and return NotFound. throw new NotFoundException($"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}: Call to TryAddPartitionKeyRangeToContinuationTokenAsync failed to the following collectionRid: {collection.ResourceId} with the supplied tokens: {JsonConvert.SerializeObject(suppliedTokens)}"); } feedRespose = response; partitionIdentifier = queryRoutingInfo.Item1.ResolvedRange.Id; } else { // For non-Windows platforms(like Linux and OSX) in .NET Core SDK, we cannot use ServiceInterop for parsing the query, // so forcing the request through Gateway. We are also now by-passing this for 32-bit host process in NETFX on Windows // as the ServiceInterop dll is only available in 64-bit. request.UseGatewayMode = true; feedRespose = await this.ExecuteRequestAsync(request, retryPolicyInstance, cancellationToken); partitionIdentifier = "Gateway"; } } return(new Tuple <DocumentFeedResponse <CosmosElement>, string>(feedRespose, partitionIdentifier)); } }
public async Task ChangeFeedIteratorCore_WithFullFidelity() { ContainerProperties properties = new ContainerProperties(id: Guid.NewGuid().ToString(), partitionKeyPath: ChangeFeedIteratorCoreTests.PartitionKey); properties.ChangeFeedPolicy.FullFidelityRetention = TimeSpan.FromMinutes(5); ContainerResponse response = await this.database.CreateContainerAsync( properties, cancellationToken : this.cancellationToken); ContainerInternal container = (ContainerInternal)response; // FF does not work with StartFromBeginning currently, so we capture an initial continuation. FeedIterator <ToDoActivityWithMetadata> fullFidelityIterator = container.GetChangeFeedIterator <ToDoActivityWithMetadata>( ChangeFeedStartFrom.Now(), ChangeFeedMode.FullFidelity); string initialContinuation = null; while (fullFidelityIterator.HasMoreResults) { try { FeedResponse <ToDoActivityWithMetadata> feedResponse = await fullFidelityIterator.ReadNextAsync(this.cancellationToken); initialContinuation = feedResponse.ContinuationToken; } catch (CosmosException cosmosException) when(cosmosException.StatusCode == HttpStatusCode.NotModified) { initialContinuation = cosmosException.Headers.ContinuationToken; break; } } // Insert documents and then delete them int totalDocuments = 50; IList <ToDoActivity> createdItems = await this.CreateRandomItems(container, totalDocuments, randomPartitionKey : true); foreach (ToDoActivity item in createdItems) { await container.DeleteItemAsync <ToDoActivity>(item.id, new PartitionKey(item.status)); } // Resume Change Feed and verify we pickup all the events fullFidelityIterator = container.GetChangeFeedIterator <ToDoActivityWithMetadata>( ChangeFeedStartFrom.ContinuationToken(initialContinuation), ChangeFeedMode.FullFidelity); int detectedEvents = 0; bool hasInserts = false; bool hasDeletes = false; while (fullFidelityIterator.HasMoreResults) { try { FeedResponse <ToDoActivityWithMetadata> feedResponse = await fullFidelityIterator.ReadNextAsync(this.cancellationToken); foreach (ToDoActivityWithMetadata item in feedResponse) { Assert.IsNotNull(item.metadata, "Metadata not present"); Assert.IsNotNull(item.metadata.operationType, "Metadata has no operationType"); hasInserts |= item.metadata.operationType == "create"; hasDeletes |= item.metadata.operationType == "delete"; } detectedEvents += feedResponse.Count; } catch (CosmosException cosmosException) when(cosmosException.StatusCode == HttpStatusCode.NotModified) { break; } } Assert.AreEqual(2 * totalDocuments, detectedEvents, "Full Fidelity should include inserts and delete events."); Assert.IsTrue(hasInserts, "No metadata for create operationType found"); Assert.IsTrue(hasDeletes, "No metadata for delete operationType found"); }
public override Task <ContainerResponse> ReplaceContainerAsync(ContainerProperties containerProperties, ContainerRequestOptions requestOptions = null, CancellationToken cancellationToken = default) { var returnValue = new CosmosContainerResponseMock(); return(Task.FromResult((ContainerResponse)returnValue)); }
public void ContainerSettingsWithIndexingPolicyTest() { string id = Guid.NewGuid().ToString(); string pkPath = "/partitionKey"; // Two equivalent definitions ContainerProperties cosmosContainerSettings = new ContainerProperties(id, pkPath); cosmosContainerSettings.IndexingPolicy.Automatic = true; cosmosContainerSettings.IndexingPolicy.IncludedPaths.Add(new Cosmos.IncludedPath() { Path = "/id1/*" }); Cosmos.UniqueKey cuk1 = new Cosmos.UniqueKey(); cuk1.Paths.Add("/u1"); cosmosContainerSettings.UniqueKeyPolicy.UniqueKeys.Add(cuk1); DocumentCollection collection = new DocumentCollection() { Id = id, PartitionKey = new PartitionKeyDefinition() { Paths = new Collection <string>() { pkPath }, } }; collection.IndexingPolicy.Automatic = true; collection.IndexingPolicy.IncludedPaths.Add(new Documents.IncludedPath() { Path = "/id1/*" }); Documents.UniqueKey duk1 = new Documents.UniqueKey(); duk1.Paths.Add("/u1"); collection.UniqueKeyPolicy.UniqueKeys.Add(duk1); string cosmosSerialized = SettingsContractTests.CosmosSerialize(cosmosContainerSettings); string directSerialized = SettingsContractTests.DirectSerialize(collection); // Swap de-serialize and validate ContainerProperties containerDeserSettings = SettingsContractTests.CosmosDeserialize <ContainerProperties>(directSerialized); DocumentCollection collectionDeser = SettingsContractTests.DirectDeSerialize <DocumentCollection>(cosmosSerialized); Assert.AreEqual(collection.Id, containerDeserSettings.Id); Assert.AreEqual(collection.PartitionKey.Paths[0], containerDeserSettings.PartitionKeyPath); Assert.AreEqual(collection.IndexingPolicy.Automatic, containerDeserSettings.IndexingPolicy.Automatic); Assert.AreEqual(collection.IndexingPolicy.IncludedPaths.Count, containerDeserSettings.IndexingPolicy.IncludedPaths.Count); Assert.AreEqual(collection.IndexingPolicy.IncludedPaths[0].Path, containerDeserSettings.IndexingPolicy.IncludedPaths[0].Path); Assert.AreEqual(collection.IndexingPolicy.IncludedPaths[0].Indexes.Count, containerDeserSettings.IndexingPolicy.IncludedPaths[0].Indexes.Count); Assert.AreEqual(collection.UniqueKeyPolicy.UniqueKeys.Count, containerDeserSettings.UniqueKeyPolicy.UniqueKeys.Count); Assert.AreEqual(collection.UniqueKeyPolicy.UniqueKeys[0].Paths.Count, containerDeserSettings.UniqueKeyPolicy.UniqueKeys[0].Paths.Count); Assert.AreEqual(collection.UniqueKeyPolicy.UniqueKeys[0].Paths[0], containerDeserSettings.UniqueKeyPolicy.UniqueKeys[0].Paths[0]); Assert.AreEqual(cosmosContainerSettings.Id, collectionDeser.Id); Assert.AreEqual(cosmosContainerSettings.PartitionKeyPath, collectionDeser.PartitionKey.Paths[0]); Assert.AreEqual(cosmosContainerSettings.IndexingPolicy.Automatic, collectionDeser.IndexingPolicy.Automatic); Assert.AreEqual(cosmosContainerSettings.IndexingPolicy.IncludedPaths.Count, collectionDeser.IndexingPolicy.IncludedPaths.Count); Assert.AreEqual(cosmosContainerSettings.IndexingPolicy.IncludedPaths[0].Path, collectionDeser.IndexingPolicy.IncludedPaths[0].Path); Assert.AreEqual(cosmosContainerSettings.IndexingPolicy.IncludedPaths[0].Indexes.Count, collectionDeser.IndexingPolicy.IncludedPaths[0].Indexes.Count); Assert.AreEqual(cosmosContainerSettings.UniqueKeyPolicy.UniqueKeys.Count, collectionDeser.UniqueKeyPolicy.UniqueKeys.Count); Assert.AreEqual(cosmosContainerSettings.UniqueKeyPolicy.UniqueKeys[0].Paths.Count, collectionDeser.UniqueKeyPolicy.UniqueKeys[0].Paths.Count); Assert.AreEqual(cosmosContainerSettings.UniqueKeyPolicy.UniqueKeys[0].Paths[0], collectionDeser.UniqueKeyPolicy.UniqueKeys[0].Paths[0]); }
public static async Task <IDocumentQueryExecutionContext> CreateDocumentQueryExecutionContextAsync( IDocumentQueryClient client, ResourceType resourceTypeEnum, Type resourceType, Expression expression, FeedOptions feedOptions, string resourceLink, bool isContinuationExpected, CancellationToken token, Guid correlatedActivityId) { ContainerProperties collection = null; if (resourceTypeEnum.IsCollectionChild()) { CollectionCache collectionCache = await client.GetCollectionCacheAsync(); using ( DocumentServiceRequest request = DocumentServiceRequest.Create( OperationType.Query, resourceTypeEnum, resourceLink, AuthorizationTokenType.Invalid)) //this request doesnt actually go to server { collection = await collectionCache.ResolveCollectionAsync(request, token, NoOpTrace.Singleton); } if (feedOptions != null && feedOptions.PartitionKey != null && feedOptions.PartitionKey.Equals(Documents.PartitionKey.None)) { feedOptions.PartitionKey = Documents.PartitionKey.FromInternalKey(collection.GetNoneValue()); } } DocumentQueryExecutionContextBase.InitParams constructorParams = new DocumentQueryExecutionContextBase.InitParams( client, resourceTypeEnum, resourceType, expression, feedOptions, resourceLink, false, correlatedActivityId); // For non-Windows platforms(like Linux and OSX) in .NET Core SDK, we cannot use ServiceInterop, so need to bypass in that case. // We are also now bypassing this for 32 bit host process running even on Windows as there are many 32 bit apps that will not work without this if (CustomTypeExtensions.ByPassQueryParsing()) { // We create a ProxyDocumentQueryExecutionContext that will be initialized with DefaultDocumentQueryExecutionContext // which will be used to send the query to Gateway and on getting 400(bad request) with 1004(cross partition query not servable), we initialize it with // PipelinedDocumentQueryExecutionContext by providing the partition query execution info that's needed(which we get from the exception returned from Gateway). ProxyDocumentQueryExecutionContext proxyQueryExecutionContext = ProxyDocumentQueryExecutionContext.Create( client, resourceTypeEnum, resourceType, expression, feedOptions, resourceLink, token, collection, isContinuationExpected, correlatedActivityId); return(proxyQueryExecutionContext); } DefaultDocumentQueryExecutionContext queryExecutionContext = await DefaultDocumentQueryExecutionContext.CreateAsync( constructorParams, isContinuationExpected, token); // If isContinuationExpected is false, we want to check if there are aggregates. if ( resourceTypeEnum.IsCollectionChild() && resourceTypeEnum.IsPartitioned() && (feedOptions.EnableCrossPartitionQuery || !isContinuationExpected)) { //todo:elasticcollections this may rely on information from collection cache which is outdated //if collection is deleted/created with same name. //need to make it not rely on information from collection cache. PartitionedQueryExecutionInfo partitionedQueryExecutionInfo = await queryExecutionContext.GetPartitionedQueryExecutionInfoAsync( partitionKeyDefinition : collection.PartitionKey, requireFormattableOrderByQuery : true, isContinuationExpected : isContinuationExpected, allowNonValueAggregateQuery : true, hasLogicalPartitionKey : feedOptions.PartitionKey != null, allowDCount : true, cancellationToken : token); if (DocumentQueryExecutionContextFactory.ShouldCreateSpecializedDocumentQueryExecutionContext( resourceTypeEnum, feedOptions, partitionedQueryExecutionInfo, collection.PartitionKey, isContinuationExpected)) { List <PartitionKeyRange> targetRanges = await GetTargetPartitionKeyRangesAsync( queryExecutionContext, partitionedQueryExecutionInfo, collection, feedOptions); // Devnote this will get replace by the new v3 to v2 logic throw new NotSupportedException("v2 query excution context is currently not supported."); } } return(queryExecutionContext); }
public async Task ContainerContractTest() { ContainerProperties containerProperties = new ContainerProperties(Guid.NewGuid().ToString(), "/users") { IndexingPolicy = new IndexingPolicy() { Automatic = true, IndexingMode = IndexingMode.Consistent, IncludedPaths = new Collection <IncludedPath>() { new IncludedPath() { Path = "/*" } }, ExcludedPaths = new Collection <ExcludedPath>() { new ExcludedPath() { Path = "/test/*" } }, CompositeIndexes = new Collection <Collection <CompositePath> >() { new Collection <CompositePath>() { new CompositePath() { Path = "/address/city", Order = CompositePathSortOrder.Ascending }, new CompositePath() { Path = "/address/zipcode", Order = CompositePathSortOrder.Descending } } }, SpatialIndexes = new Collection <SpatialPath>() { new SpatialPath() { Path = "/address/spatial/*", SpatialTypes = new Collection <SpatialType>() { SpatialType.LineString } } } } }; CosmosJsonDotNetSerializer serializer = new CosmosJsonDotNetSerializer(); Stream stream = serializer.ToStream(containerProperties); ContainerProperties deserialziedTest = serializer.FromStream <ContainerProperties>(stream); ContainerResponse response = await this.database.CreateContainerAsync(containerProperties); Assert.IsNotNull(response); Assert.IsTrue(response.RequestCharge > 0); Assert.IsNotNull(response.Headers); Assert.IsNotNull(response.Headers.ActivityId); ContainerProperties responseProperties = response.Resource; Assert.IsNotNull(responseProperties.Id); Assert.IsNotNull(responseProperties.ResourceId); Assert.IsNotNull(responseProperties.ETag); Assert.IsTrue(responseProperties.LastModified.HasValue); Assert.IsTrue(responseProperties.LastModified.Value > new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), responseProperties.LastModified.Value.ToString()); Assert.AreEqual(1, responseProperties.IndexingPolicy.IncludedPaths.Count); IncludedPath includedPath = responseProperties.IndexingPolicy.IncludedPaths.First(); Assert.AreEqual("/*", includedPath.Path); Assert.AreEqual("/test/*", responseProperties.IndexingPolicy.ExcludedPaths.First().Path); Assert.AreEqual(1, responseProperties.IndexingPolicy.CompositeIndexes.Count); Assert.AreEqual(2, responseProperties.IndexingPolicy.CompositeIndexes.First().Count); CompositePath compositePath = responseProperties.IndexingPolicy.CompositeIndexes.First().First(); Assert.AreEqual("/address/city", compositePath.Path); Assert.AreEqual(CompositePathSortOrder.Ascending, compositePath.Order); Assert.AreEqual(1, responseProperties.IndexingPolicy.SpatialIndexes.Count); SpatialPath spatialPath = responseProperties.IndexingPolicy.SpatialIndexes.First(); Assert.AreEqual("/address/spatial/*", spatialPath.Path); Assert.AreEqual(1, spatialPath.SpatialTypes.Count); Assert.AreEqual(SpatialType.LineString, spatialPath.SpatialTypes.First()); }
private async Task ValidateCollectionIndexProgressHeaders(CosmosClient client) { Cosmos.Database db = await client.CreateDatabaseAsync(Guid.NewGuid().ToString()); try { PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition { Paths = new System.Collections.ObjectModel.Collection <string>(new[] { "/id" }), Kind = PartitionKind.Hash }; var lazyCollection = new ContainerProperties() { Id = Guid.NewGuid().ToString(), PartitionKey = partitionKeyDefinition }; lazyCollection.IndexingPolicy.IndexingMode = Cosmos.IndexingMode.Lazy; Container lazyContainer = await db.CreateContainerAsync(lazyCollection); var consistentCollection = new ContainerProperties() { Id = Guid.NewGuid().ToString(), PartitionKey = partitionKeyDefinition }; consistentCollection.IndexingPolicy.IndexingMode = Cosmos.IndexingMode.Consistent; Container consistentContainer = await db.CreateContainerAsync(consistentCollection); var noneIndexCollection = new ContainerProperties() { Id = Guid.NewGuid().ToString(), PartitionKey = partitionKeyDefinition }; noneIndexCollection.IndexingPolicy.Automatic = false; noneIndexCollection.IndexingPolicy.IndexingMode = Cosmos.IndexingMode.None; Container noneIndexContainer = await db.CreateContainerAsync(noneIndexCollection); var doc = new Document() { Id = Guid.NewGuid().ToString() }; await lazyContainer.CreateItemAsync <Document>(doc); await consistentContainer.CreateItemAsync <Document>(doc); await noneIndexContainer.CreateItemAsync <Document>(doc); // Lazy-indexing collection. { ContainerResponse collectionResponse = await lazyContainer.ReadAsync(requestOptions : new ContainerRequestOptions { PopulateQuotaInfo = true }); Assert.IsTrue(int.Parse(collectionResponse.Headers[HttpConstants.HttpHeaders.CollectionLazyIndexingProgress], CultureInfo.InvariantCulture) >= 0, "Expect lazy indexer progress when reading lazy collection."); Assert.AreEqual(100, int.Parse(collectionResponse.Headers[HttpConstants.HttpHeaders.CollectionIndexTransformationProgress], CultureInfo.InvariantCulture), "Expect reindexer progress when reading lazy collection."); } // Consistent-indexing collection. { ContainerResponse collectionResponse = await consistentContainer.ReadAsync(requestOptions : new ContainerRequestOptions { PopulateQuotaInfo = true }); Assert.IsFalse(collectionResponse.Headers.AllKeys().Contains(HttpConstants.HttpHeaders.CollectionLazyIndexingProgress), "No lazy indexer progress when reading consistent collection."); Assert.AreEqual(100, int.Parse(collectionResponse.Headers[HttpConstants.HttpHeaders.CollectionIndexTransformationProgress], CultureInfo.InvariantCulture), "Expect reindexer progress when reading consistent collection."); } // None-indexing collection. { ContainerResponse collectionResponse = await noneIndexContainer.ReadAsync(requestOptions : new ContainerRequestOptions { PopulateQuotaInfo = true }); Assert.IsFalse(collectionResponse.Headers.AllKeys().Contains(HttpConstants.HttpHeaders.CollectionLazyIndexingProgress), "No lazy indexer progress when reading none-index collection."); Assert.AreEqual(100, int.Parse(collectionResponse.Headers[HttpConstants.HttpHeaders.CollectionIndexTransformationProgress], CultureInfo.InvariantCulture), "Expect reindexer progress when reading none-index collection."); } } finally { await db.DeleteAsync(); } }
private async Task DataUpdateStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken) { var orderData = await _orderDataAccessor.GetAsync(stepContext.Context, () => new OrderData(), cancellationToken); CosmosClient client = new CosmosClient(Startup.CosmosDbEndpoint, Startup.AuthKey); database = await client.CreateDatabaseIfNotExistsAsync(databaseId); ContainerProperties containerProperties = new ContainerProperties(containerId, partitionKeyPath: Startup.PartitionKey); // Create with a throughput of 1000 RU/s container = await database.CreateContainerIfNotExistsAsync( containerProperties, throughput : 1000); //orderNum 가져오기 try { FeedIterator <DBdata> feedIterator = container.GetItemQueryIterator <DBdata>("SELECT top 1 * FROM c order by c._ts desc"); { while (feedIterator.HasMoreResults) { FeedResponse <DBdata> result = await feedIterator.ReadNextAsync(); foreach (var item in result) { orderData.OrderNum = Int32.Parse(item.id); } } } } catch (System.Exception e) { orderData.OrderNum = 0; } //ip IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); string ipAddr = string.Empty; for (int i = 0; i < host.AddressList.Length; i++) { if (host.AddressList[i].AddressFamily == AddressFamily.InterNetwork) { ipAddr = host.AddressList[i].ToString(); } } //Order 데이터 삽입 foreach (Sandwich tempSand in orderData.Sandwiches) { string sJson = JsonConvert.SerializeObject(tempSand); var dbData = new DBdata { id = $"{++orderData.OrderNum}", Contents = tempSand, ETag = "x", AccountNumber = ipAddr }; await container.CreateItemAsync <DBdata>(dbData, new PartitionKey(dbData.AccountNumber)); } //container 변경 containerProperties = new ContainerProperties(countContainerId, partitionKeyPath: "/AccountNumber"); // Create with a throughput of 1000 RU/s container = await database.CreateContainerIfNotExistsAsync( containerProperties, throughput : 1000); //Count 데이터 삽입 foreach (Sandwich tempSand in orderData.Sandwiches) { var CountId = 0; string sauce = ""; tempSand.Sauce.Sort(); foreach (string temp in tempSand.Sauce) { sauce += temp + " "; } //CountId 찾기 try { FeedIterator <DBcount> feedIterator = container.GetItemQueryIterator <DBcount>("SELECT top 1 * FROM c order by c._ts desc"); { while (feedIterator.HasMoreResults) { FeedResponse <DBcount> result = await feedIterator.ReadNextAsync(); foreach (var item in result) { CountId = Int32.Parse(item.id) + 1; } } } } catch (System.Exception e) { CountId = 0; } try { FeedIterator <DBcount> feedIterator = container.GetItemQueryIterator <DBcount>("SELECT * FROM c WHERE c.Sauce='" + sauce + "' and c.Bread ='" + tempSand.Bread + "' and c.Menu ='" + tempSand.Menu + "'"); { if (feedIterator.HasMoreResults) { FeedResponse <DBcount> result = await feedIterator.ReadNextAsync(); DBcount res = result.First(); var count = res.Count + 1; DBcount countData = new DBcount(); countData.id = res.id; countData.Count = count; countData.Sauce = sauce; countData.Menu = tempSand.Menu; countData.ETag = "x"; countData.AccountNumber = "0"; countData.Bread = tempSand.Bread; ItemResponse <DBcount> item = await container.DeleteItemAsync <DBcount>(partitionKey : new PartitionKey("0"), id : res.id); await container.CreateItemAsync(countData, new PartitionKey("0")); } } } catch (System.Exception e) { var countData = new DBcount { id = $"{CountId}", Count = 1, Bread = $"{tempSand.Bread}", Sauce = sauce, Menu = $"{tempSand.Menu}", ETag = "x", AccountNumber = "0" }; await container.CreateItemAsync <DBcount>(countData, new PartitionKey("0")); } } }
public async Task CreateContainerIfNotExistsAsyncTest() { string containerName = Guid.NewGuid().ToString(); string partitionKeyPath1 = "/users"; ContainerProperties settings = new ContainerProperties(containerName, partitionKeyPath1); ContainerResponse containerResponse = await this.cosmosDatabase.CreateContainerIfNotExistsAsync(settings); Assert.AreEqual(HttpStatusCode.Created, containerResponse.StatusCode); Assert.AreEqual(containerName, containerResponse.Resource.Id); Assert.AreEqual(partitionKeyPath1, containerResponse.Resource.PartitionKey.Paths.First()); //Creating container with same partition key path containerResponse = await this.cosmosDatabase.CreateContainerIfNotExistsAsync(settings); Assert.AreEqual(HttpStatusCode.OK, containerResponse.StatusCode); Assert.AreEqual(containerName, containerResponse.Resource.Id); Assert.AreEqual(partitionKeyPath1, containerResponse.Resource.PartitionKey.Paths.First()); //Creating container with different partition key path string partitionKeyPath2 = "/users2"; try { settings = new ContainerProperties(containerName, partitionKeyPath2); containerResponse = await this.cosmosDatabase.CreateContainerIfNotExistsAsync(settings); Assert.Fail("Should through ArgumentException on partition key path"); } catch (ArgumentException ex) { Assert.AreEqual(nameof(settings.PartitionKey), ex.ParamName); Assert.IsTrue(ex.Message.Contains(string.Format( ClientResources.PartitionKeyPathConflict, partitionKeyPath2, containerName, partitionKeyPath1))); } containerResponse = await containerResponse.Container.DeleteContainerAsync(); Assert.AreEqual(HttpStatusCode.NoContent, containerResponse.StatusCode); //Creating existing container with partition key having value for SystemKey //https://github.com/Azure/azure-cosmos-dotnet-v3/issues/623 string v2ContainerName = "V2Container"; PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); partitionKeyDefinition.Paths.Add("/test"); partitionKeyDefinition.IsSystemKey = false; ContainerProperties containerPropertiesWithSystemKey = new ContainerProperties() { Id = v2ContainerName, PartitionKey = partitionKeyDefinition, }; await this.cosmosDatabase.CreateContainerAsync(containerPropertiesWithSystemKey); ContainerProperties containerProperties = new ContainerProperties(v2ContainerName, "/test"); containerResponse = await this.cosmosDatabase.CreateContainerIfNotExistsAsync(containerProperties); Assert.AreEqual(HttpStatusCode.OK, containerResponse.StatusCode); Assert.AreEqual(v2ContainerName, containerResponse.Resource.Id); Assert.AreEqual("/test", containerResponse.Resource.PartitionKey.Paths.First()); containerResponse = await containerResponse.Container.DeleteContainerAsync(); Assert.AreEqual(HttpStatusCode.NoContent, containerResponse.StatusCode); containerPropertiesWithSystemKey.PartitionKey.IsSystemKey = true; await this.cosmosDatabase.CreateContainerAsync(containerPropertiesWithSystemKey); containerProperties = new ContainerProperties(v2ContainerName, "/test"); containerResponse = await this.cosmosDatabase.CreateContainerIfNotExistsAsync(containerProperties); Assert.AreEqual(HttpStatusCode.OK, containerResponse.StatusCode); Assert.AreEqual(v2ContainerName, containerResponse.Resource.Id); Assert.AreEqual("/test", containerResponse.Resource.PartitionKey.Paths.First()); containerResponse = await containerResponse.Container.DeleteContainerAsync(); Assert.AreEqual(HttpStatusCode.NoContent, containerResponse.StatusCode); }
/// <summary> /// Creates a container with the current fluent definition. /// </summary> /// <param name="throughput">Desired throughput for the container expressed in Request Units per second.</param> /// <returns>An asynchronous Task representing the creation of a <see cref="Container"/> based on the Fluent definition.</returns> /// <remarks> /// <seealso href="https://docs.microsoft.com/azure/cosmos-db/request-units"/> for details on provision throughput. /// </remarks> public virtual async Task <ContainerResponse> CreateAsync(int?throughput = null) { ContainerProperties containerProperties = this.Build(); return(await this.cosmosContainers.CreateContainerAsync(containerProperties, throughput)); }
/// <summary> /// Resolves a request to a collection in a sticky manner. /// Unless request.ForceNameCacheRefresh is equal to true, it will return the same collection. /// </summary> /// <param name="request">Request to resolve.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <param name="trace">The trace.</param> /// <returns>Instance of <see cref="ContainerProperties"/>.</returns> public virtual async Task <ContainerProperties> ResolveCollectionAsync( DocumentServiceRequest request, CancellationToken cancellationToken, ITrace trace) { IClientSideRequestStatistics clientSideRequestStatistics = request.RequestContext?.ClientRequestStatistics; if (request.IsNameBased) { if (request.ForceNameCacheRefresh) { await this.RefreshAsync(request, trace, clientSideRequestStatistics, cancellationToken); request.ForceNameCacheRefresh = false; } ContainerProperties collectionInfo = await this.ResolveByPartitionKeyRangeIdentityAsync( request.Headers[HttpConstants.HttpHeaders.Version], request.PartitionKeyRangeIdentity, trace, clientSideRequestStatistics, cancellationToken); if (collectionInfo != null) { return(collectionInfo); } if (request.RequestContext.ResolvedCollectionRid == null) { collectionInfo = await this.ResolveByNameAsync( apiVersion : request.Headers[HttpConstants.HttpHeaders.Version], resourceAddress : request.ResourceAddress, forceRefesh : false, trace : trace, clientSideRequestStatistics : clientSideRequestStatistics, cancellationToken : cancellationToken); if (collectionInfo != null) { DefaultTrace.TraceVerbose( "Mapped resourceName {0} to resourceId {1}. '{2}'", request.ResourceAddress, collectionInfo.ResourceId, System.Diagnostics.Trace.CorrelationManager.ActivityId); request.ResourceId = collectionInfo.ResourceId; request.RequestContext.ResolvedCollectionRid = collectionInfo.ResourceId; } else { DefaultTrace.TraceVerbose( "Collection with resourceName {0} not found. '{1}'", request.ResourceAddress, System.Diagnostics.Trace.CorrelationManager.ActivityId); } return(collectionInfo); } else { return(await this.ResolveByRidAsync(request.Headers[HttpConstants.HttpHeaders.Version], request.RequestContext.ResolvedCollectionRid, trace, clientSideRequestStatistics, cancellationToken)); } } else { return(await this.ResolveByPartitionKeyRangeIdentityAsync(request.Headers[HttpConstants.HttpHeaders.Version], request.PartitionKeyRangeIdentity, trace, clientSideRequestStatistics, cancellationToken) ?? await this.ResolveByRidAsync(request.Headers[HttpConstants.HttpHeaders.Version], request.ResourceAddress, trace, clientSideRequestStatistics, cancellationToken)); } }
public async Task InsertWithUniqueIndex() { ContainerProperties collectionSpec = new ContainerProperties { Id = "InsertWithUniqueIndexConstraint_" + Guid.NewGuid(), PartitionKeyPath = defaultPartitionKeyDefinition, UniqueKeyPolicy = new UniqueKeyPolicy { UniqueKeys = new Collection <UniqueKey> { new UniqueKey { Paths = new Collection <string> { "/name", "/address" } } } }, IndexingPolicy = new IndexingPolicy { IndexingMode = IndexingMode.Consistent, IncludedPaths = new Collection <IncludedPath> { new IncludedPath { Path = "/name/?", Indexes = new Collection <Index> { new HashIndex(DataType.String, 7) } }, new IncludedPath { Path = "/address/?", Indexes = new Collection <Index> { new HashIndex(DataType.String, 7) } }, }, ExcludedPaths = new Collection <ExcludedPath> { new ExcludedPath { Path = "/*" } } } }; Func <Container, Task> testFunction = async(Container container) => { dynamic doc1 = new { id = Guid.NewGuid().ToString(), name = "Alexander Pushkin", pk = "test", address = "Russia 630090" }; dynamic doc1Conflict = new { id = Guid.NewGuid().ToString(), name = doc1.name, pk = doc1.pk, address = doc1.address }; dynamic doc1Conflict2 = new { id = Guid.NewGuid().ToString(), name = doc1.name, pk = doc1.pk, address = doc1.address }; dynamic doc2 = new { id = Guid.NewGuid().ToString(), name = "Alexander Pushkin", pk = "test", address = "Russia 640000" }; dynamic doc3 = new { id = Guid.NewGuid().ToString(), name = "Mihkail Lermontov", pk = "test", address = "Russia 630090" }; await container.CreateItemAsync <dynamic>(doc1); try { await container.CreateItemAsync <dynamic>(doc1Conflict); Assert.Fail("Did not throw due to unique constraint (create)"); } catch (CosmosException ex) { Assert.AreEqual(HttpStatusCode.Conflict, ex.StatusCode, $"Expected:Conflict, Actual:{ex.StatusCode}; Exception:ex.ToString()"); } try { await container.UpsertItemAsync <dynamic>(doc1Conflict2); Assert.Fail("Did not throw due to unique constraint (upsert)"); } catch (CosmosException ex) { // Search for: L"For upsert insert, if it failed with E_RESOURCE_ALREADY_EXISTS, return E_CONCURRENCY_VIOLATION so that client will retry" Assert.AreEqual(HttpStatusCode.Conflict, ex.StatusCode, $"Expected:Conflict, Actual:{ex.StatusCode}; Exception:ex.ToString()"); } await container.CreateItemAsync <dynamic>(doc2); await container.CreateItemAsync <dynamic>(doc3); }; await this.TestForEachClient(collectionSpec, testFunction, "InsertWithUniqueIndex"); }
public void ValidateResponseFactoryJsonSerializer() { ResponseMessage databaseResponse = this.CreateResponse(); ResponseMessage containerResponse = this.CreateResponse(); ResponseMessage storedProcedureExecuteResponse = this.CreateResponse(); ResponseMessage storedProcedureResponse = this.CreateResponse(); ResponseMessage triggerResponse = this.CreateResponse(); ResponseMessage udfResponse = this.CreateResponse(); ResponseMessage itemResponse = this.CreateResponse(); Mock <CosmosSerializer> mockUserJsonSerializer = new Mock <CosmosSerializer>(); CosmosSerializerCore serializerCore = new CosmosSerializerCore(mockUserJsonSerializer.Object); CosmosResponseFactoryInternal cosmosResponseFactory = new CosmosResponseFactoryCore( serializerCore); // Test the user specified response mockUserJsonSerializer.Setup(x => x.FromStream <ToDoActivity>(itemResponse.Content)).Callback <Stream>(input => input.Dispose()).Returns(new ToDoActivity()); mockUserJsonSerializer.Setup(x => x.FromStream <ToDoActivity>(storedProcedureExecuteResponse.Content)).Callback <Stream>(input => input.Dispose()).Returns(new ToDoActivity()); // Verify all the user types use the user specified version cosmosResponseFactory.CreateItemResponse <ToDoActivity>(itemResponse); cosmosResponseFactory.CreateStoredProcedureExecuteResponse <ToDoActivity>(storedProcedureExecuteResponse); // Throw if the setups were not called mockUserJsonSerializer.VerifyAll(); // Test read feed scenario ResponseMessage readFeedResponse = this.CreateReadFeedResponse(); mockUserJsonSerializer.Setup(x => x.FromStream <ToDoActivity[]>(It.IsAny <Stream>())) .Callback <Stream>(input => input.Dispose()) .Returns(new ToDoActivity[] { new ToDoActivity() }); FeedResponse <ToDoActivity> feedResponse = cosmosResponseFactory.CreateItemFeedResponse <ToDoActivity>(readFeedResponse); foreach (ToDoActivity toDoActivity in feedResponse) { Assert.IsNotNull(toDoActivity); } mockUserJsonSerializer.VerifyAll(); ResponseMessage changeFeedResponseMessage = this.CreateChangeFeedNotModifiedResponse(); try { cosmosResponseFactory.CreateItemFeedResponse <ToDoActivity>(changeFeedResponseMessage); Assert.Fail(); } catch (CosmosException cosmosException) { Assert.AreEqual(HttpStatusCode.NotModified, cosmosException.StatusCode); } ResponseMessage queryResponse = this.CreateReadFeedResponse(); mockUserJsonSerializer.Setup(x => x.FromStream <ToDoActivity[]>(It.IsAny <Stream>())).Callback <Stream>(input => input.Dispose()).Returns(new ToDoActivity[] { new ToDoActivity() }); FeedResponse <ToDoActivity> queryFeedResponse = cosmosResponseFactory.CreateItemFeedResponse <ToDoActivity>(queryResponse); foreach (ToDoActivity toDoActivity in queryFeedResponse) { Assert.IsNotNull(toDoActivity); } mockUserJsonSerializer.VerifyAll(); // Test the system specified response ContainerProperties containerSettings = new ContainerProperties("mockId", "/pk"); DatabaseProperties databaseSettings = new DatabaseProperties() { Id = "mock" }; StoredProcedureProperties cosmosStoredProcedureSettings = new StoredProcedureProperties() { Id = "mock" }; TriggerProperties cosmosTriggerSettings = new TriggerProperties() { Id = "mock" }; UserDefinedFunctionProperties cosmosUserDefinedFunctionSettings = new UserDefinedFunctionProperties() { Id = "mock" }; Mock <Container> mockContainer = new Mock <Container>(); Mock <Database> mockDatabase = new Mock <Database>(); // Verify all the system types that should always use default cosmosResponseFactory.CreateContainerResponse(mockContainer.Object, containerResponse); cosmosResponseFactory.CreateDatabaseResponse(mockDatabase.Object, databaseResponse); cosmosResponseFactory.CreateStoredProcedureResponse(storedProcedureResponse); cosmosResponseFactory.CreateTriggerResponse(triggerResponse); cosmosResponseFactory.CreateUserDefinedFunctionResponse(udfResponse); }
public async Task ContainerMigrationTest() { string containerName = "MigrationIndexTest"; Documents.Index index1 = new Documents.RangeIndex(Documents.DataType.String, -1); Documents.Index index2 = new Documents.RangeIndex(Documents.DataType.Number, -1); Documents.DocumentCollection documentCollection = new Microsoft.Azure.Documents.DocumentCollection() { Id = containerName, IndexingPolicy = new Documents.IndexingPolicy() { IncludedPaths = new Collection <Documents.IncludedPath>() { new Documents.IncludedPath() { Path = "/*", Indexes = new Collection <Documents.Index>() { index1, index2 } } } } }; Documents.DocumentCollection createResponse = await NonPartitionedContainerHelper.CreateNonPartitionedContainer(this.database, documentCollection); // Verify the collection was created with deprecated Index objects Assert.AreEqual(2, createResponse.IndexingPolicy.IncludedPaths.First().Indexes.Count); Documents.Index createIndex = createResponse.IndexingPolicy.IncludedPaths.First().Indexes.First(); Assert.AreEqual(index1.Kind, createIndex.Kind); // Verify v3 can add composite indexes and update the container Container container = this.database.GetContainer(containerName); ContainerProperties containerProperties = await container.ReadContainerAsync(); string cPath0 = "/address/city"; string cPath1 = "/address/state"; containerProperties.IndexingPolicy.CompositeIndexes.Add(new Collection <CompositePath>() { new CompositePath() { Path = cPath0, Order = CompositePathSortOrder.Descending }, new CompositePath() { Path = cPath1, Order = CompositePathSortOrder.Ascending } }); containerProperties.IndexingPolicy.SpatialIndexes.Add( new SpatialPath() { Path = "/address/test/*", SpatialTypes = new Collection <SpatialType>() { SpatialType.Point } }); ContainerProperties propertiesAfterReplace = await container.ReplaceContainerAsync(containerProperties); Assert.AreEqual(0, propertiesAfterReplace.IndexingPolicy.IncludedPaths.First().Indexes.Count); Assert.AreEqual(1, propertiesAfterReplace.IndexingPolicy.CompositeIndexes.Count); Collection <CompositePath> compositePaths = propertiesAfterReplace.IndexingPolicy.CompositeIndexes.First(); Assert.AreEqual(2, compositePaths.Count); CompositePath compositePath0 = compositePaths.ElementAt(0); CompositePath compositePath1 = compositePaths.ElementAt(1); Assert.IsTrue(string.Equals(cPath0, compositePath0.Path) || string.Equals(cPath1, compositePath0.Path)); Assert.IsTrue(string.Equals(cPath0, compositePath1.Path) || string.Equals(cPath1, compositePath1.Path)); Assert.AreEqual(1, propertiesAfterReplace.IndexingPolicy.SpatialIndexes.Count); Assert.AreEqual("/address/test/*", propertiesAfterReplace.IndexingPolicy.SpatialIndexes.First().Path); }
public async Task NoPartitionedCreateFail() { string containerName = Guid.NewGuid().ToString(); try { new ContainerProperties(id: containerName, partitionKeyPath: null); Assert.Fail("Create should throw null ref exception"); } catch (ArgumentNullException ae) { Assert.IsNotNull(ae); } try { new ContainerProperties(id: containerName, partitionKeyDefinition: null); Assert.Fail("Create should throw null ref exception"); } catch (ArgumentNullException ae) { Assert.IsNotNull(ae); } ContainerProperties settings = new ContainerProperties() { Id = containerName }; try { ContainerResponse containerResponse = await this.cosmosDatabase.CreateContainerAsync(settings); Assert.Fail("Create should throw null ref exception"); } catch (ArgumentNullException ae) { Assert.IsNotNull(ae); } try { ContainerResponse containerResponse = await this.cosmosDatabase.CreateContainerIfNotExistsAsync(settings); Assert.Fail("Create should throw null ref exception"); } catch (ArgumentNullException ae) { Assert.IsNotNull(ae); } try { ContainerResponse containerResponse = await this.cosmosDatabase.CreateContainerAsync(id : containerName, partitionKeyPath : null); Assert.Fail("Create should throw null ref exception"); } catch (ArgumentNullException ae) { Assert.IsNotNull(ae); } try { ContainerResponse containerResponse = await this.cosmosDatabase.CreateContainerIfNotExistsAsync(id : containerName, partitionKeyPath : null); Assert.Fail("Create should throw null ref exception"); } catch (ArgumentNullException ae) { Assert.IsNotNull(ae); } }
public DefaultCosmosContainerProvider( ICosmosClientProvider cosmosClientProvider, ICosmosPartitionKeyPathProvider cosmosPartitionKeyPathProvider, IOptions <RepositoryOptions> options, ILogger <DefaultCosmosContainerProvider <TItem> > logger) { _cosmosClientProvider = cosmosClientProvider ?? throw new ArgumentNullException( nameof(cosmosClientProvider), "Cosmos client provider is required."); _cosmosPartitionKeyPathProvider = cosmosPartitionKeyPathProvider ?? throw new ArgumentNullException( nameof(cosmosPartitionKeyPathProvider), "Cosmos partition key name provider is required."); _options = options?.Value ?? throw new ArgumentNullException( nameof(options), "Repository options are required."); if (_options.CosmosConnectionString is null) { throw new ArgumentNullException($"The {nameof(_options.CosmosConnectionString)} is required."); } if (_options.DatabaseId is null) { throw new ArgumentNullException($"The {nameof(_options.DatabaseId)} is required."); } if (_options.ContainerId is null) { throw new ArgumentNullException($"The {nameof(_options.ContainerId)} is required."); } if (logger is null) { throw new ArgumentNullException($"The {nameof(logger)} is required."); } _logger = logger; _lazyContainer = new Lazy <Task <Container> >(async() => { try { Database database = await _cosmosClientProvider.UseClientAsync( client => client.CreateDatabaseIfNotExistsAsync(_options.DatabaseId)); ContainerProperties containerProperties = new ContainerProperties { Id = _options.ContainerPerItemType ? typeof(TItem).Name : _options.ContainerId, PartitionKeyPath = _cosmosPartitionKeyPathProvider.GetPartitionKeyPath <TItem>() }; Container container = await database.CreateContainerIfNotExistsAsync( containerProperties); return(container); } catch (Exception ex) { _logger.LogError(ex.Message, ex); throw; } }); }
public async Task TimeToLivePropertyPath() { string containerName = Guid.NewGuid().ToString(); string partitionKeyPath = "/user"; int timeToLivetimeToLiveInSeconds = 10; ContainerProperties setting = new ContainerProperties() { Id = containerName, PartitionKey = new PartitionKeyDefinition() { Paths = new Collection <string> { partitionKeyPath }, Kind = PartitionKind.Hash }, TimeToLivePropertyPath = "/creationDate", }; ContainerResponse containerResponse = null; try { containerResponse = await this.cosmosDatabase.CreateContainerIfNotExistsAsync(setting); Assert.Fail("CreateColleciton with TtlPropertyPath and with no DefaultTimeToLive should have failed."); } catch (CosmosException exeption) { // expected because DefaultTimeToLive was not specified Assert.AreEqual(HttpStatusCode.BadRequest, exeption.StatusCode); } // Verify the container content. setting.DefaultTimeToLive = timeToLivetimeToLiveInSeconds; containerResponse = await this.cosmosDatabase.CreateContainerIfNotExistsAsync(setting); Container container = containerResponse; Assert.AreEqual(timeToLivetimeToLiveInSeconds, containerResponse.Resource.DefaultTimeToLive); Assert.AreEqual("/creationDate", containerResponse.Resource.TimeToLivePropertyPath); //verify removing the ttl property path setting.TimeToLivePropertyPath = null; containerResponse = await container.ReplaceContainerAsync(setting); container = containerResponse; Assert.AreEqual(timeToLivetimeToLiveInSeconds, containerResponse.Resource.DefaultTimeToLive); Assert.IsNull(containerResponse.Resource.TimeToLivePropertyPath); //adding back the ttl property path setting.TimeToLivePropertyPath = "/creationDate"; containerResponse = await container.ReplaceContainerAsync(setting); container = containerResponse; Assert.AreEqual(containerResponse.Resource.TimeToLivePropertyPath, "/creationDate"); //Creating an item and reading before expiration var payload = new { id = "testId", user = "******", creationDate = ToEpoch(DateTime.UtcNow) }; ItemResponse <dynamic> createItemResponse = await container.CreateItemAsync <dynamic>(payload); Assert.IsNotNull(createItemResponse.Resource); Assert.AreEqual(createItemResponse.StatusCode, HttpStatusCode.Created); ItemResponse <dynamic> readItemResponse = await container.ReadItemAsync <dynamic>(payload.id, new Cosmos.PartitionKey(payload.user)); Assert.IsNotNull(readItemResponse.Resource); Assert.AreEqual(readItemResponse.StatusCode, HttpStatusCode.OK); containerResponse = await container.DeleteContainerAsync(); Assert.AreEqual(HttpStatusCode.NoContent, containerResponse.StatusCode); }
public override Task <ResponseMessage> ReplaceContainerStreamAsync(ContainerProperties containerProperties, ContainerRequestOptions requestOptions = null, CancellationToken cancellationToken = default) { var returnValue = new ResponseMessage(); return(Task.FromResult(returnValue)); }
private void Init() { this.collectionCache = new Mock <ClientCollectionCache>(new SessionContainer("testhost"), new ServerStoreModel(null), null, null); const string pkPath = "/pk"; this.collectionCache.Setup (m => m.ResolveCollectionAsync( It.IsAny <DocumentServiceRequest>(), It.IsAny <CancellationToken>() ) ).Returns(() => { ContainerProperties cosmosContainerSetting = ContainerProperties.CreateWithResourceId("test"); cosmosContainerSetting.PartitionKey = new PartitionKeyDefinition() { Kind = PartitionKind.Hash, Paths = new Collection <string>() { pkPath } }; return(Task.FromResult(cosmosContainerSetting)); }); this.collectionCache.Setup (m => m.ResolveByNameAsync( It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>() ) ).Returns(() => { ContainerProperties containerSettings = ContainerProperties.CreateWithResourceId("test"); containerSettings.PartitionKey.Paths = new Collection <string>() { pkPath }; return(Task.FromResult(containerSettings)); }); this.collectionCache.Setup (m => m.ResolveByNameAsync( It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CancellationToken>() ) ).Returns(() => { ContainerProperties cosmosContainerSetting = ContainerProperties.CreateWithResourceId("test"); cosmosContainerSetting.PartitionKey = new PartitionKeyDefinition() { Kind = PartitionKind.Hash, Paths = new Collection <string>() { pkPath } }; return(Task.FromResult(cosmosContainerSetting)); }); this.partitionKeyRangeCache = new Mock <PartitionKeyRangeCache>(null, null, null); this.partitionKeyRangeCache.Setup( m => m.TryLookupAsync( It.IsAny <string>(), It.IsAny <CollectionRoutingMap>(), It.IsAny <DocumentServiceRequest>(), It.IsAny <CancellationToken>() ) ).Returns(Task.FromResult <CollectionRoutingMap>(null)); this.partitionKeyRangeCache.Setup( m => m.TryGetOverlappingRangesAsync( It.IsAny <string>(), It.IsAny <Documents.Routing.Range <string> >(), It.IsAny <bool>() ) ).Returns((string collectionRid, Documents.Routing.Range <string> range, bool forceRefresh) => { return(Task.FromResult <IReadOnlyList <PartitionKeyRange> >(this.ResolveOverlapingPartitionKeyRanges(collectionRid, range, forceRefresh))); }); this.globalEndpointManager = new Mock <GlobalEndpointManager>(this, new ConnectionPolicy()); SessionContainer sessionContainer = new SessionContainer(this.ServiceEndpoint.Host); this.sessionContainer = sessionContainer; }
public async Task ContainerV2CompatTest() { string containerId = "SerializeContainerTest"; DocumentCollection documentCollection = new DocumentCollection() { Id = containerId, PartitionKey = new PartitionKeyDefinition() { Paths = new Collection <string>() { "/pkPath" } }, IndexingPolicy = new IndexingPolicy() { IncludedPaths = new Collection <IncludedPath>() { new IncludedPath() { Path = "/*" } }, CompositeIndexes = new Collection <Collection <CompositePath> >() { new Collection <CompositePath>() { new CompositePath() { Path = "/address/test/*", Order = CompositePathSortOrder.Ascending }, new CompositePath() { Path = "/address/test2/*", Order = CompositePathSortOrder.Ascending } } }, SpatialIndexes = new Collection <SpatialSpec>() { new SpatialSpec() { Path = "/name/first/*", SpatialTypes = new Collection <SpatialType>() { SpatialType.LineString } } } }, }; string documentJsonString = null; using (MemoryStream memoryStream = new MemoryStream()) { documentCollection.SaveTo(memoryStream); memoryStream.Position = 0; using (StreamReader sr = new StreamReader(memoryStream)) { documentJsonString = await sr.ReadToEndAsync(); } } Assert.IsNotNull(documentJsonString); string cosmosJsonString = null; using (MemoryStream memoryStream = new MemoryStream()) { documentCollection.SaveTo(memoryStream); memoryStream.Position = 0; CosmosJsonDotNetSerializer cosmosSerializer = new CosmosJsonDotNetSerializer(); ContainerProperties containerProperties = cosmosSerializer.FromStream <ContainerProperties>(memoryStream); Assert.IsNotNull(containerProperties); Assert.AreEqual(containerId, containerProperties.Id); using (Stream stream = cosmosSerializer.ToStream <ContainerProperties>(containerProperties)) { using (StreamReader sr = new StreamReader(stream)) { cosmosJsonString = await sr.ReadToEndAsync(); } } } JObject jObjectDocumentCollection = JObject.Parse(documentJsonString); JObject jObjectContainer = JObject.Parse(cosmosJsonString); Assert.IsTrue(JToken.DeepEquals(jObjectDocumentCollection, jObjectContainer)); }
public async Task ValidateResponseFactoryJsonSerializer() { ResponseMessage databaseResponse = this.CreateResponse(); ResponseMessage containerResponse = this.CreateResponse(); ResponseMessage storedProcedureExecuteResponse = this.CreateResponse(); ResponseMessage storedProcedureResponse = this.CreateResponse(); ResponseMessage triggerResponse = this.CreateResponse(); ResponseMessage udfResponse = this.CreateResponse(); ResponseMessage itemResponse = this.CreateResponse(); ResponseMessage feedResponse = this.CreateResponse(); Mock <CosmosSerializer> mockUserJsonSerializer = new Mock <CosmosSerializer>(); Mock <CosmosSerializer> mockDefaultJsonSerializer = new Mock <CosmosSerializer>(); CosmosResponseFactory cosmosResponseFactory = new CosmosResponseFactory( defaultJsonSerializer: mockDefaultJsonSerializer.Object, userJsonSerializer: mockUserJsonSerializer.Object); // Test the user specified response mockUserJsonSerializer.Setup(x => x.FromStream <ToDoActivity>(itemResponse.Content)).Returns(new ToDoActivity()); mockUserJsonSerializer.Setup(x => x.FromStream <ToDoActivity>(storedProcedureExecuteResponse.Content)).Returns(new ToDoActivity()); mockUserJsonSerializer.Setup(x => x.FromStream <CosmosFeedResponseUtil <ToDoActivity> >(feedResponse.Content)).Returns(new CosmosFeedResponseUtil <ToDoActivity>() { Data = new Collection <ToDoActivity>() }); // Verify all the user types use the user specified version await cosmosResponseFactory.CreateItemResponseAsync <ToDoActivity>(Task.FromResult(itemResponse)); await cosmosResponseFactory.CreateStoredProcedureExecuteResponseAsync <ToDoActivity>(Task.FromResult(storedProcedureExecuteResponse)); cosmosResponseFactory.CreateQueryFeedResponse <ToDoActivity>(feedResponse); // Throw if the setups were not called mockUserJsonSerializer.VerifyAll(); // Test the system specified response ContainerProperties containerSettings = new ContainerProperties("mockId", "/pk"); DatabaseProperties databaseSettings = new DatabaseProperties() { Id = "mock" }; StoredProcedureProperties cosmosStoredProcedureSettings = new StoredProcedureProperties() { Id = "mock" }; TriggerProperties cosmosTriggerSettings = new TriggerProperties() { Id = "mock" }; UserDefinedFunctionProperties cosmosUserDefinedFunctionSettings = new UserDefinedFunctionProperties() { Id = "mock" }; mockDefaultJsonSerializer.Setup(x => x.FromStream <DatabaseProperties>(databaseResponse.Content)).Returns(databaseSettings); mockDefaultJsonSerializer.Setup(x => x.FromStream <ContainerProperties>(containerResponse.Content)).Returns(containerSettings); mockDefaultJsonSerializer.Setup(x => x.FromStream <StoredProcedureProperties>(storedProcedureResponse.Content)).Returns(cosmosStoredProcedureSettings); mockDefaultJsonSerializer.Setup(x => x.FromStream <TriggerProperties>(triggerResponse.Content)).Returns(cosmosTriggerSettings); mockDefaultJsonSerializer.Setup(x => x.FromStream <UserDefinedFunctionProperties>(udfResponse.Content)).Returns(cosmosUserDefinedFunctionSettings); Mock <Container> mockContainer = new Mock <Container>(); Mock <Database> mockDatabase = new Mock <Database>(); // Verify all the system types that should always use default await cosmosResponseFactory.CreateContainerResponseAsync(mockContainer.Object, Task.FromResult(containerResponse)); await cosmosResponseFactory.CreateDatabaseResponseAsync(mockDatabase.Object, Task.FromResult(databaseResponse)); await cosmosResponseFactory.CreateStoredProcedureResponseAsync(Task.FromResult(storedProcedureResponse)); await cosmosResponseFactory.CreateTriggerResponseAsync(Task.FromResult(triggerResponse)); await cosmosResponseFactory.CreateUserDefinedFunctionResponseAsync(Task.FromResult(udfResponse)); // Throw if the setups were not called mockDefaultJsonSerializer.VerifyAll(); }
private async Task <Tuple <PartitionRoutingHelper.ResolvedRangeInfo, IReadOnlyList <Range <string> > > > TryGetTargetPartitionKeyRangeAsync( DocumentServiceRequest request, ContainerProperties collection, QueryPartitionProvider queryPartitionProvider, IRoutingMapProvider routingMapProvider, Range <string> rangeFromContinuationToken, List <CompositeContinuationToken> suppliedTokens) { string version = request.Headers[HttpConstants.HttpHeaders.Version]; version = string.IsNullOrEmpty(version) ? HttpConstants.Versions.CurrentVersion : version; bool enableCrossPartitionQuery = false; string enableCrossPartitionQueryHeader = request.Headers[HttpConstants.HttpHeaders.EnableCrossPartitionQuery]; if (enableCrossPartitionQueryHeader != null) { if (!bool.TryParse(enableCrossPartitionQueryHeader, out enableCrossPartitionQuery)) { throw new BadRequestException( string.Format( CultureInfo.InvariantCulture, RMResources.InvalidHeaderValue, enableCrossPartitionQueryHeader, HttpConstants.HttpHeaders.EnableCrossPartitionQuery)); } } IReadOnlyList <Range <string> > providedRanges; if (!this.providedRangesCache.TryGetValue(collection.ResourceId, out providedRanges)) { if (this.ShouldExecuteQueryRequest) { FeedOptions feedOptions = this.GetFeedOptions(null); PartitionKeyDefinition partitionKeyDefinition; if ((feedOptions.Properties != null) && feedOptions.Properties.TryGetValue( DefaultDocumentQueryExecutionContext.InternalPartitionKeyDefinitionProperty, out object partitionKeyDefinitionObject)) { if (partitionKeyDefinitionObject is PartitionKeyDefinition definition) { partitionKeyDefinition = definition; } else { throw new ArgumentException( "partitionkeydefinition has invalid type", nameof(partitionKeyDefinitionObject)); } } else { partitionKeyDefinition = collection.PartitionKey; } providedRanges = PartitionRoutingHelper.GetProvidedPartitionKeyRanges( querySpecJsonString: JsonConvert.SerializeObject(this.QuerySpec), enableCrossPartitionQuery: enableCrossPartitionQuery, parallelizeCrossPartitionQuery: false, isContinuationExpected: this.isContinuationExpected, hasLogicalPartitionKey: false, allowDCount: false, allowNonValueAggregates: false, useSystemPrefix: false, partitionKeyDefinition: partitionKeyDefinition, queryPartitionProvider: queryPartitionProvider, clientApiVersion: version, out QueryInfo _); } else if (request.Properties != null && request.Properties.TryGetValue( WFConstants.BackendHeaders.EffectivePartitionKeyString, out object effectivePartitionKey)) { if (effectivePartitionKey is string effectivePartitionKeyString) { providedRanges = new List <Range <string> >() { Range <string> .GetPointRange(effectivePartitionKeyString), }; } else { throw new ArgumentException( "EffectivePartitionKey must be a string", WFConstants.BackendHeaders.EffectivePartitionKeyString); } } else { providedRanges = new List <Range <string> > { new Range <string>( PartitionKeyInternal.MinimumInclusiveEffectivePartitionKey, PartitionKeyInternal.MaximumExclusiveEffectivePartitionKey, true, false) }; } this.providedRangesCache[collection.ResourceId] = providedRanges; } PartitionRoutingHelper.ResolvedRangeInfo resolvedRangeInfo = await this.partitionRoutingHelper.TryGetTargetRangeFromContinuationTokenRangeAsync( providedRanges, routingMapProvider, collection.ResourceId, rangeFromContinuationToken, suppliedTokens, NoOpTrace.Singleton); if (resolvedRangeInfo.ResolvedRange == null) { return(null); } else { return(Tuple.Create(resolvedRangeInfo, providedRanges)); } }
/// <summary> /// Replaces (deletes and creates) the <b>Cosmos</b> container (and optionally created the database if it does not exist). /// </summary> /// <param name="client">The <see cref="CosmosClient"/>.</param> /// <param name="databaseId">The database identifier.</param> /// <param name="containerProperties">The <see cref="ContainerProperties"/> used for the create.</param> /// <param name="throughput">The throughput (RU/S).</param> /// <param name="createDatabaseIfNotExists">Indicates whether the database shoould be created if it does not exist.</param> /// <returns>The <see cref="CosmosDbContainerSetUp"/>.</returns> public static async Task <CosmosDbContainerSetUp> ReplaceAndOpenAsync(CosmosClient client, string databaseId, ContainerProperties containerProperties, int?throughput = 400, bool createDatabaseIfNotExists = true) { Logger.Default.Info($"COSMOS > Database '{databaseId}' Container '{containerProperties.Id}' Replace and Open."); Check.NotNull(client, nameof(client)); Check.NotNull(containerProperties, nameof(containerProperties)); var database = client.GetDatabase(Check.NotEmpty(databaseId, nameof(databaseId))); if (createDatabaseIfNotExists) { database = (await client.CreateDatabaseIfNotExistsAsync(databaseId, throughput)).Database; } var container = database.GetContainer(containerProperties.Id); // Remove existing container if it already exists. try { await container.DeleteContainerAsync(); } catch (CosmosException cex) { if (cex.StatusCode != HttpStatusCode.NotFound) { throw; } } // Create the container as specified. await database.CreateContainerIfNotExistsAsync(containerProperties, throughput); return(new CosmosDbContainerSetUp(database, container)); }
/// <summary> /// The default behavior is for DocumentDB to index every attribute in every document automatically. /// There are times when a document contains large amounts of information, in deeply nested structures /// that you know you will never search on. In extreme cases like this, you can exclude paths from the /// index to save on storage cost, improve write performance and also improve read performance because the index is smaller /// /// This method demonstrates how to set IndexingPolicy.ExcludedPaths /// </summary> private static async Task ExcludePathsFromIndex() { string containerId = $"{Program.containerId}-ExcludePathsFromIndex"; Console.WriteLine("\n3. Exclude specified paths from document index"); ContainerProperties containerProperties = new ContainerProperties(containerId, Program.partitionKey); containerProperties.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = "/*" }); // Special manadatory path of "/*" required to denote include entire tree containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = "/metaData/*" }); // exclude metaData node, and anything under it containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = "/subDoc/nonSearchable/*" }); // exclude ONLY a part of subDoc containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = "/\"excludedNode\"/*" }); // exclude excludedNode node, and anything under it // The effect of the above IndexingPolicy is that only id, foo, and the subDoc/searchable are indexed ContainerResponse response = await Program.database.CreateContainerAsync(containerProperties); Console.WriteLine("Container {0} created with index policy \n{1}", containerId, JsonConvert.SerializeObject(response.Resource.IndexingPolicy)); Container container = (Container)response; try { int numDocs = 250; Console.WriteLine("Creating {0} documents", numDocs); for (int docIndex = 0; docIndex < numDocs; docIndex++) { dynamic dyn = new { id = "doc" + docIndex, partitionKey = "doc" + docIndex, foo = "bar" + docIndex, metaData = "meta" + docIndex, subDoc = new { searchable = "searchable" + docIndex, nonSearchable = "value" + docIndex }, excludedNode = new { subExcluded = "something" + docIndex, subExcludedNode = new { someProperty = "value" + docIndex } } }; ItemResponse <dynamic> created = await container.CreateItemAsync <dynamic>(dyn, new PartitionKey("doc" + docIndex)); Console.WriteLine("Creating document with id {0}", created.Resource.id); } // Querying for a document on either metaData or /subDoc/subSubDoc/someProperty will be expensive since they do not utilize the index, // but instead are served from scan automatically. int queryDocId = numDocs / 2; QueryStats queryStats = await Program.GetQueryResult(container, string.Format(CultureInfo.InvariantCulture, "SELECT * FROM root r WHERE r.metaData='meta{0}'", queryDocId)); Console.WriteLine("Query on metaData returned {0} results", queryStats.Count); Console.WriteLine("Query on metaData consumed {0} RUs", queryStats.RequestCharge); queryStats = await Program.GetQueryResult(container, string.Format(CultureInfo.InvariantCulture, "SELECT * FROM root r WHERE r.subDoc.nonSearchable='value{0}'", queryDocId)); Console.WriteLine("Query on /subDoc/nonSearchable returned {0} results", queryStats.Count); Console.WriteLine("Query on /subDoc/nonSearchable consumed {0} RUs", queryStats.RequestCharge); queryStats = await Program.GetQueryResult(container, string.Format(CultureInfo.InvariantCulture, "SELECT * FROM root r WHERE r.excludedNode.subExcludedNode.someProperty='value{0}'", queryDocId)); Console.WriteLine("Query on /excludedNode/subExcludedNode/someProperty returned {0} results", queryStats.Count); Console.WriteLine("Query on /excludedNode/subExcludedNode/someProperty cost {0} RUs", queryStats.RequestCharge); // Querying for a document using foo, or even subDoc/searchable > consume less RUs because they were not excluded queryStats = await Program.GetQueryResult(container, string.Format(CultureInfo.InvariantCulture, "SELECT * FROM root r WHERE r.foo='bar{0}'", queryDocId)); Console.WriteLine("Query on /foo returned {0} results", queryStats.Count); Console.WriteLine("Query on /foo cost {0} RUs", queryStats.RequestCharge); queryStats = await Program.GetQueryResult(container, string.Format(CultureInfo.InvariantCulture, "SELECT * FROM root r WHERE r.subDoc.searchable='searchable{0}'", queryDocId)); Console.WriteLine("Query on /subDoc/searchable returned {0} results", queryStats.Count); Console.WriteLine("Query on /subDoc/searchable cost {0} RUs", queryStats.RequestCharge); } finally { // Cleanup await container.DeleteContainerAsync(); } }
public static Func <bool, IQueryable <Family> > GenerateFamilyCosmosData( Cosmos.Database cosmosDatabase, out Container container) { // The test collection should have range index on string properties // for the orderby tests PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition { Paths = new System.Collections.ObjectModel.Collection <string>(new[] { "/Pk" }), Kind = PartitionKind.Hash }; ContainerProperties newCol = new ContainerProperties() { Id = Guid.NewGuid().ToString(), PartitionKey = partitionKeyDefinition, IndexingPolicy = new Microsoft.Azure.Cosmos.IndexingPolicy() { IncludedPaths = new Collection <Cosmos.IncludedPath>() { new Cosmos.IncludedPath() { Path = "/*", Indexes = new System.Collections.ObjectModel.Collection <Microsoft.Azure.Cosmos.Index>() { Microsoft.Azure.Cosmos.Index.Range(Microsoft.Azure.Cosmos.DataType.Number, -1), Microsoft.Azure.Cosmos.Index.Range(Microsoft.Azure.Cosmos.DataType.String, -1) } } }, CompositeIndexes = new Collection <Collection <Cosmos.CompositePath> >() { new Collection <Cosmos.CompositePath>() { new Cosmos.CompositePath() { Path = "/FamilyId", Order = Cosmos.CompositePathSortOrder.Ascending }, new Cosmos.CompositePath() { Path = "/Int", Order = Cosmos.CompositePathSortOrder.Ascending } }, new Collection <Cosmos.CompositePath>() { new Cosmos.CompositePath() { Path = "/FamilyId", Order = Cosmos.CompositePathSortOrder.Ascending }, new Cosmos.CompositePath() { Path = "/Int", Order = Cosmos.CompositePathSortOrder.Descending } }, new Collection <Cosmos.CompositePath>() { new Cosmos.CompositePath() { Path = "/FamilyId", Order = Cosmos.CompositePathSortOrder.Ascending }, new Cosmos.CompositePath() { Path = "/Int", Order = Cosmos.CompositePathSortOrder.Ascending }, new Cosmos.CompositePath() { Path = "/IsRegistered", Order = Cosmos.CompositePathSortOrder.Descending } }, new Collection <Cosmos.CompositePath>() { new Cosmos.CompositePath() { Path = "/Int", Order = Cosmos.CompositePathSortOrder.Ascending }, new Cosmos.CompositePath() { Path = "/IsRegistered", Order = Cosmos.CompositePathSortOrder.Descending } }, new Collection <Cosmos.CompositePath>() { new Cosmos.CompositePath() { Path = "/IsRegistered", Order = Cosmos.CompositePathSortOrder.Ascending }, new Cosmos.CompositePath() { Path = "/Int", Order = Cosmos.CompositePathSortOrder.Descending } } } } }; container = cosmosDatabase.CreateContainerAsync(newCol).Result; const int Records = 100; const int MaxNameLength = 100; const int MaxThingStringLength = 50; const int MaxChild = 5; const int MaxPets = MaxChild; const int MaxThings = MaxChild; const int MaxGrade = 101; const int MaxTransaction = 20; const int MaxTransactionMinuteRange = 200; int MaxTransactionType = Enum.GetValues(typeof(TransactionType)).Length; Family createDataObj(Random random) { Family obj = new Family { FamilyId = random.NextDouble() < 0.05 ? "some id" : Guid.NewGuid().ToString(), IsRegistered = random.NextDouble() < 0.5, NullableInt = random.NextDouble() < 0.5 ? (int?)random.Next() : null, Int = random.NextDouble() < 0.5 ? 5 : random.Next(), Id = Guid.NewGuid().ToString(), Pk = "Test", Parents = new Parent[random.Next(2) + 1] }; for (int i = 0; i < obj.Parents.Length; ++i) { obj.Parents[i] = new Parent() { FamilyName = LinqTestsCommon.RandomString(random, random.Next(MaxNameLength)), GivenName = LinqTestsCommon.RandomString(random, random.Next(MaxNameLength)) }; } obj.Tags = new string[random.Next(MaxChild)]; for (int i = 0; i < obj.Tags.Length; ++i) { obj.Tags[i] = (i + random.Next(30, 36)).ToString(); } obj.Children = new Child[random.Next(MaxChild)]; for (int i = 0; i < obj.Children.Length; ++i) { obj.Children[i] = new Child() { Gender = random.NextDouble() < 0.5 ? "male" : "female", FamilyName = obj.Parents[random.Next(obj.Parents.Length)].FamilyName, GivenName = LinqTestsCommon.RandomString(random, random.Next(MaxNameLength)), Grade = random.Next(MaxGrade) }; obj.Children[i].Pets = new List <Pet>(); for (int j = 0; j < random.Next(MaxPets); ++j) { obj.Children[i].Pets.Add(new Pet() { GivenName = random.NextDouble() < 0.5 ? LinqTestsCommon.RandomString(random, random.Next(MaxNameLength)) : "Fluffy" }); } obj.Children[i].Things = new Dictionary <string, string>(); for (int j = 0; j < random.Next(MaxThings) + 1; ++j) { obj.Children[i].Things.Add( j == 0 ? "A" : $"{j}-{random.Next().ToString()}", LinqTestsCommon.RandomString(random, random.Next(MaxThingStringLength))); } } obj.Records = new Logs { LogId = LinqTestsCommon.RandomString(random, random.Next(MaxNameLength)), Transactions = new Transaction[random.Next(MaxTransaction)] }; for (int i = 0; i < obj.Records.Transactions.Length; ++i) { Transaction transaction = new Transaction() { Amount = random.Next(), Date = DateTime.Now.AddMinutes(random.Next(MaxTransactionMinuteRange)), Type = (TransactionType)random.Next(MaxTransactionType) }; obj.Records.Transactions[i] = transaction; } return(obj); } Func <bool, IQueryable <Family> > getQuery = LinqTestsCommon.GenerateTestCosmosData(createDataObj, Records, container); return(getQuery); }