internal DocumentClient BindForClient(CosmosDBAttribute attribute) { string resolvedConnectionString = ResolveConnectionString(attribute.ConnectionStringSetting); ICosmosDBService service = GetService(resolvedConnectionString, attribute.PreferredLocations, attribute.UseMultipleWriteLocations); return(service.GetClient()); }
internal DocumentClient BindForClient(CosmosDBAttribute attribute) { string resolvedConnectionString = ResolveConnectionString(attribute.ConnectionStringSetting); ICosmosDBService service = GetService(resolvedConnectionString); return(service.GetClient()); }
public async Task <IEnumerable <T> > ConvertAsync(CosmosDBAttribute attribute, CancellationToken cancellationToken) { CosmosDBContext context = _config.CreateContext(attribute); Uri collectionUri = UriFactory.CreateDocumentCollectionUri(context.ResolvedAttribute.DatabaseName, context.ResolvedAttribute.CollectionName); List <T> finalResults = new List <T>(); string continuation = null; SqlQuerySpec sqlSpec = new SqlQuerySpec { QueryText = context.ResolvedAttribute.SqlQuery, Parameters = context.ResolvedAttribute.SqlQueryParameters ?? new SqlParameterCollection() }; do { DocumentQueryResponse <T> response = await context.Service.ExecuteNextAsync <T>(collectionUri, sqlSpec, continuation); finalResults.AddRange(response.Results); continuation = response.ResponseContinuation; }while (!string.IsNullOrEmpty(continuation)); return(finalResults); }
internal void ValidateConnection(CosmosDBAttribute attribute, Type paramType) { if (string.IsNullOrEmpty(attribute.ConnectionStringSetting)) { string attributeProperty = $"{nameof(CosmosDBAttribute)}.{nameof(CosmosDBAttribute.ConnectionStringSetting)}"; throw new InvalidOperationException( $"The CosmosDB connection string must be set via the {attributeProperty} property."); } }
internal CosmosDBBindingContext CreateContext(CosmosDBAttribute attribute) { CosmosClient client = GetService(attribute.ConnectionStringSetting, attribute.CurrentRegion); return(new CosmosDBBindingContext { CosmosClient = client, ResolvedAttribute = attribute, }); }
internal void ValidateConnection(CosmosDBAttribute attribute, Type paramType) { if (string.IsNullOrEmpty(_options.ConnectionString) && string.IsNullOrEmpty(attribute.ConnectionStringSetting)) { string attributeProperty = $"{nameof(CosmosDBAttribute)}.{nameof(CosmosDBAttribute.ConnectionStringSetting)}"; string optionsProperty = $"{nameof(CosmosDBOptions)}.{nameof(CosmosDBOptions.ConnectionString)}"; throw new InvalidOperationException( $"The CosmosDB connection string must be set either via the '{Constants.DefaultConnectionStringName}' IConfiguration connection string, via the {attributeProperty} property or via {optionsProperty}."); } }
internal CosmosDBContext CreateContext(CosmosDBAttribute attribute) { string resolvedConnectionString = ResolveConnectionString(attribute.ConnectionStringSetting); ICosmosDBService service = GetService(resolvedConnectionString, attribute.PreferredLocations, attribute.UseMultipleWriteLocations); return(new CosmosDBContext { Service = service, ResolvedAttribute = attribute, }); }
internal void ValidateConnection(CosmosDBAttribute attribute, Type paramType) { if (string.IsNullOrEmpty(_options.ConnectionString) && string.IsNullOrEmpty(attribute.ConnectionStringSetting) && string.IsNullOrEmpty(_defaultConnectionString)) { throw new InvalidOperationException( string.Format(CultureInfo.CurrentCulture, "The CosmosDB connection string must be set either via a '{0}' app setting, via the CosmosDBAttribute.ConnectionStringSetting property or via CosmosDBConfiguration.ConnectionString.", AzureWebJobsCosmosDBConnectionStringName)); } }
internal CosmosDBContext CreateContext(CosmosDBAttribute attribute) { string resolvedConnectionString = ResolveConnectionString(attribute.ConnectionStringSetting); ICosmosDBService service = GetService(resolvedConnectionString); return(new CosmosDBContext { Service = service, ResolvedAttribute = attribute, }); }
internal Task <IValueBinder> BindForItemAsync(CosmosDBAttribute attribute, Type type) { if (string.IsNullOrEmpty(attribute.Id)) { throw new InvalidOperationException("The 'Id' property of a CosmosDB single-item input binding cannot be null or empty."); } CosmosDBContext context = CreateContext(attribute); Type genericType = typeof(CosmosDBItemValueBinder <>).MakeGenericType(type); IValueBinder binder = (IValueBinder)Activator.CreateInstance(genericType, context); return(Task.FromResult(binder)); }
public static CosmosDBContext CreateContext(ICosmosDBService service, bool createIfNotExists = false, string partitionKeyPath = null, int throughput = 0) { CosmosDBAttribute attribute = new CosmosDBAttribute(CosmosDBTestUtility.DatabaseName, CosmosDBTestUtility.CollectionName) { CreateIfNotExists = createIfNotExists, PartitionKey = partitionKeyPath, CollectionThroughput = throughput }; return(new CosmosDBContext { Service = service, ResolvedAttribute = attribute }); }
public static async void Run([ServiceBusTrigger("msciprovider", "mscicompany", Connection = "MsciConnectionString")] string mySbMsg, IBinder binder, ILogger log) { var collectionName = "CandriamContainer"; var attribute = new CosmosDBAttribute("CandriamDB", collectionName) { CreateIfNotExists = true, ConnectionStringSetting = "CosmosDBConnection", }; var collector = await binder.BindAsync <IAsyncCollector <dynamic> >(attribute); await collector.AddAsync(new { Message = mySbMsg, id = Guid.NewGuid(), ProviderId = 2 }); log.LogInformation("Document created !"); }
private static CosmosDBItemValueBinder <T> CreateBinder <T>(out Mock <ICosmosDBService> mockService, string partitionKey = null) where T : class { mockService = new Mock <ICosmosDBService>(MockBehavior.Strict); CosmosDBAttribute attribute = new CosmosDBAttribute(DatabaseName, CollectionName) { Id = Id, PartitionKey = partitionKey }; var context = new CosmosDBContext { ResolvedAttribute = attribute, Service = mockService.Object }; return(new CosmosDBItemValueBinder <T>(context)); }
public async Task Configuration_Caches_Clients() { // Arrange var config = new CosmosDBConfiguration { ConnectionString = "AccountEndpoint=https://someuri;AccountKey=c29tZV9rZXk=;", }; var attribute = new CosmosDBAttribute { Id = "abcdef" }; // Act var context1 = config.CreateContext(attribute); var context2 = config.CreateContext(attribute); var binder = await config.BindForItemAsync(attribute, typeof(Item)); // Assert Assert.Single(config.ClientCache); }
public async Task Configuration_Caches_Clients() { // Arrange var options = new CosmosDBOptions { ConnectionString = "AccountEndpoint=https://someuri;AccountKey=c29tZV9rZXk=;" }; var config = new CosmosDBExtensionConfigProvider(new OptionsWrapper <CosmosDBOptions>(options), new DefaultCosmosDBServiceFactory(), new TestNameResolver(), NullLoggerFactory.Instance); var attribute = new CosmosDBAttribute { Id = "abcdef" }; // Act var context1 = config.CreateContext(attribute); var context2 = config.CreateContext(attribute); var binder = await config.BindForItemAsync(attribute, typeof(Item)); // Assert Assert.Single(config.ClientCache); }
public void TemplateBind_DuplicateParameters() { // Arrange PropertyInfo propInfo = null; CosmosDBAttribute resolvedAttribute = new CosmosDBAttribute(); BindingTemplate bindingTemplate = BindingTemplate.FromString("SELECT * FROM c WHERE c.id = {foo} AND c.value = {foo}"); Dictionary <string, object> bindingData = new Dictionary <string, object>(); bindingData.Add("foo", "1234"); CosmosDBSqlResolutionPolicy policy = new CosmosDBSqlResolutionPolicy(); // Act string result = policy.TemplateBind(propInfo, resolvedAttribute, bindingTemplate, bindingData); // Assert Assert.Single(resolvedAttribute.SqlQueryParameters, p => p.Name == "@foo" && p.Value.ToString() == "1234"); Assert.Equal("SELECT * FROM c WHERE c.id = @foo AND c.value = @foo", result); }
public async Task ConvertAsync_RethrowsException_IfNotFound() { var builder = CreateBuilder <Item>(out Mock <ICosmosDBService> mockService); mockService .Setup(m => m.ExecuteNextAsync <Item>(_expectedUri, It.IsAny <SqlQuerySpec>(), It.IsAny <string>())) .ThrowsAsync(CosmosDBTestUtility.CreateDocumentClientException((HttpStatusCode)404)); CosmosDBAttribute attribute = new CosmosDBAttribute(DatabaseName, CollectionName) { SqlQuery = string.Empty, SqlQueryParameters = new SqlParameterCollection() }; var ex = await Assert.ThrowsAsync <DocumentClientException>(() => builder.ConvertAsync(attribute, CancellationToken.None)); Assert.Equal("NotFound", ex.Error.Code); mockService.Verify(m => m.ExecuteNextAsync <Item>(_expectedUri, It.IsAny <SqlQuerySpec>(), It.IsAny <string>()), Times.Once()); }
public async Task SetAsync_Updates_IfPropertyChanges() { // Arrange var mockService = new Mock <ICosmosDBService>(MockBehavior.Strict); Item original = new Item { Id = "abc123", Text = "hello" }; Item updated = new Item { Id = "abc123", Text = "goodbye" }; mockService .Setup(m => m.ReplaceDocumentAsync(_expectedUri, updated)) .ReturnsAsync(new Document()); CosmosDBAttribute attribute = new CosmosDBAttribute(DatabaseName, CollectionName) { Id = Id }; var context = new CosmosDBContext { Service = mockService.Object, ResolvedAttribute = attribute }; JObject clonedOrig = CosmosDBItemValueBinder <object> .CloneItem(original); // Act await CosmosDBItemValueBinder <Item> .SetValueInternalAsync(clonedOrig, updated, context); // Assert mockService.VerifyAll(); }
public async Task ConvertAsync_Succeeds_NoContinuation() { var builder = CreateBuilder <Document>(out Mock <ICosmosDBService> mockService); mockService .Setup(m => m.ExecuteNextAsync <Document>(_expectedUri, It.IsAny <SqlQuerySpec>(), It.IsAny <string>())) .ReturnsAsync(new DocumentQueryResponse <Document> { Results = GetDocumentCollection(5), ResponseContinuation = null }); CosmosDBAttribute attribute = new CosmosDBAttribute(DatabaseName, CollectionName) { SqlQuery = string.Empty, SqlQueryParameters = new SqlParameterCollection() }; var results = await builder.ConvertAsync(attribute, CancellationToken.None); Assert.Equal(5, results.Count()); }
internal static void ValidateInputBinding(CosmosDBAttribute attribute, Type parameterType) { bool hasSqlQuery = !string.IsNullOrEmpty(attribute.SqlQuery); bool hasId = !string.IsNullOrEmpty(attribute.Id); if (hasSqlQuery && hasId) { throw new InvalidOperationException($"Only one of 'SqlQuery' and '{nameof(CosmosDBAttribute.Id)}' can be specified."); } if (IsSupportedEnumerable(parameterType)) { if (hasId) { throw new InvalidOperationException($"'{nameof(CosmosDBAttribute.Id)}' cannot be specified when binding to an IEnumerable property."); } } else if (!hasId) { throw new InvalidOperationException($"'{nameof(CosmosDBAttribute.Id)}' is required when binding to a {parameterType.Name} property."); } }
public async Task ConvertAsync_Succeeds_WithContinuation() { var builder = CreateBuilder <Document>(out Mock <ICosmosDBService> mockService); var docCollection = GetDocumentCollection(17); mockService .SetupSequence(m => m.ExecuteNextAsync <Document>(_expectedUri, It.IsAny <SqlQuerySpec>(), It.IsAny <string>())) .ReturnsAsync(new DocumentQueryResponse <Document> { Results = docCollection.Take(5), ResponseContinuation = "1" }) .ReturnsAsync(new DocumentQueryResponse <Document> { Results = docCollection.Skip(5).Take(5), ResponseContinuation = "2" }).ReturnsAsync(new DocumentQueryResponse <Document> { Results = docCollection.Skip(10).Take(5), ResponseContinuation = "3" }).ReturnsAsync(new DocumentQueryResponse <Document> { Results = docCollection.Skip(15).Take(2), ResponseContinuation = null }); CosmosDBAttribute attribute = new CosmosDBAttribute(DatabaseName, CollectionName) { SqlQuery = string.Empty, SqlQueryParameters = new SqlParameterCollection() }; var results = await builder.ConvertAsync(attribute, CancellationToken.None); Assert.Equal(17, results.Count()); mockService.Verify(m => m.ExecuteNextAsync <Document>(_expectedUri, It.IsAny <SqlQuerySpec>(), It.IsAny <string>()), Times.Exactly(4)); }
public async Task SetAsync_Poco_SkipsUpdate_IfSame() { // Arrange var mockService = new Mock <ICosmosDBService>(MockBehavior.Strict); Item original = new Item { Id = "abc123", Text = "hello" }; Item updated = new Item { Id = "abc123", Text = "hello" }; CosmosDBAttribute attribute = new CosmosDBAttribute(DatabaseName, CollectionName) { Id = Id }; var context = new CosmosDBContext { Service = mockService.Object, ResolvedAttribute = attribute }; JObject clonedOrig = CosmosDBItemValueBinder <object> .CloneItem(original); // Act await CosmosDBItemValueBinder <Item> .SetValueInternalAsync(clonedOrig, updated, context); // Assert // nothing on the client should be called mockService.VerifyAll(); }
public string TemplateBind(PropertyInfo propInfo, Attribute resolvedAttribute, BindingTemplate bindingTemplate, IReadOnlyDictionary <string, object> bindingData) { if (bindingTemplate == null) { throw new ArgumentNullException(nameof(bindingTemplate)); } if (bindingData == null) { throw new ArgumentNullException(nameof(bindingData)); } CosmosDBAttribute docDbAttribute = resolvedAttribute as CosmosDBAttribute; if (docDbAttribute == null) { throw new NotSupportedException($"This policy is only supported for {nameof(CosmosDBAttribute)}."); } // build a SqlParameterCollection for each parameter SqlParameterCollection paramCollection = new SqlParameterCollection(); // also build up a dictionary replacing '{token}' with '@token' IDictionary <string, string> replacements = new Dictionary <string, string>(); foreach (var token in bindingTemplate.ParameterNames.Distinct()) { string sqlToken = $"@{token}"; paramCollection.Add(new SqlParameter(sqlToken, bindingData[token])); replacements.Add(token, sqlToken); } docDbAttribute.SqlQueryParameters = paramCollection; string replacement = bindingTemplate.Bind(new ReadOnlyDictionary <string, string>(replacements)); return(replacement); }
public async Task <IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "api/orders")] HttpRequest req, IBinder binder, ILogger log) { log.LogInformation("GetOrders HTTP trigger function processed a request."); if (!await req.CheckAuthorization("api")) { return(new UnauthorizedResult()); } var cosmosDb = new CosmosDBAttribute("ordersservice", "data"); cosmosDb.ConnectionStringSetting = "CosmosDB"; var ordersData = await binder.BindAsync <IEnumerable <NewOrderMessage> >(cosmosDb); var orders = ordersData.Select(doc => doc.Order).OrderByDescending(o => o.Created).ToList(); return(new OkObjectResult(orders)); }
public async Task SetAsync_Poco_Throws_IfIdChanges() { // Arrange var mockService = new Mock <ICosmosDBService>(MockBehavior.Strict); Item original = new Item { Id = "abc123", }; Item updated = new Item { Id = "def456", }; CosmosDBAttribute attribute = new CosmosDBAttribute(DatabaseName, CollectionName) { Id = Id }; var context = new CosmosDBContext { Service = mockService.Object, ResolvedAttribute = attribute }; var originalJson = JObject.FromObject(original); // Act var ex = await Assert.ThrowsAsync <InvalidOperationException>( () => CosmosDBItemValueBinder <Item> .SetValueInternalAsync(originalJson, updated, context)); // Assert Assert.Equal("Cannot update the 'Id' property.", ex.Message); mockService.Verify(); }
public void ValidateInputBindings_Succeeds_WithValidBindings(CosmosDBAttribute attribute, Type parameterType) { CosmosDBConfiguration.ValidateInputBinding(attribute, parameterType); }
public IAsyncCollector <T> Convert(CosmosDBAttribute attribute) { CosmosDBContext context = _configProvider.CreateContext(attribute); return(new CosmosDBAsyncCollector <T>(context)); }
public void ValidateInputBindings_Throws_WithInvalidBindings(CosmosDBAttribute attribute, Type parameterType) { Assert.Throws <InvalidOperationException>(() => CosmosDBConfiguration.ValidateInputBinding(attribute, parameterType)); }