public override Collection <Attribute> GetAttributes() { Collection <Attribute> attributes = new Collection <Attribute>(); string databaseName = Context.GetMetadataValue <string>("databaseName"); string collectionName = Context.GetMetadataValue <string>("collectionName"); DocumentDBAttribute attribute = null; if (!string.IsNullOrEmpty(databaseName) || !string.IsNullOrEmpty(collectionName)) { attribute = new DocumentDBAttribute(databaseName, collectionName); } else { attribute = new DocumentDBAttribute(); } attribute.CreateIfNotExists = Context.GetMetadataValue <bool>("createIfNotExists"); attribute.ConnectionStringSetting = Context.GetMetadataValue <string>("connection"); attribute.Id = Context.GetMetadataValue <string>("id"); attribute.PartitionKey = Context.GetMetadataValue <string>("partitionKey"); attribute.CollectionThroughput = Context.GetMetadataValue <int>("collectionThroughput"); attributes.Add(attribute); return(attributes); }
public override async Task BindAsync(BindingContext context) { DocumentDBAttribute attribute = new DocumentDBAttribute(DatabaseName, CollectionName) { CreateIfNotExists = CreateIfNotExists, ConnectionString = ConnectionString, Id = Id }; RuntimeBindingContext runtimeContext = new RuntimeBindingContext(attribute); if (Access == FileAccess.Read && _bindingDirection == BindingDirection.In) { JObject input = await context.Binder.BindAsync <JObject>(runtimeContext); if (input != null) { byte[] byteArray = Encoding.UTF8.GetBytes(input.ToString()); using (MemoryStream stream = new MemoryStream(byteArray)) { stream.CopyTo(context.Value); } } } else if (Access == FileAccess.Write && _bindingDirection == BindingDirection.Out) { await BindAsyncCollectorAsync <JObject>(context.Value, context.Binder, runtimeContext); } }
public void GetAttributeBuilderInfo_DocumentDBAttribute() { DocumentDBAttribute attribute = new DocumentDBAttribute("myDb", "myCollection") { CreateIfNotExists = true, ConnectionStringSetting = "myConnection", PartitionKey = "myPartition", Id = "myId", CollectionThroughput = 123 }; var builderInfo = ExtensionBinding.GetAttributeBuilderInfo(attribute); DocumentDBAttribute result = (DocumentDBAttribute)builderInfo.Constructor.Invoke(builderInfo.ConstructorArgs); Assert.Equal(attribute.DatabaseName, result.DatabaseName); Assert.Equal(attribute.CollectionName, result.CollectionName); Assert.Equal(5, builderInfo.Properties.Count); var properties = builderInfo.Properties.ToDictionary(p => p.Key.Name, p => p.Value); Assert.True((bool)properties["CreateIfNotExists"]); Assert.Equal("myConnection", (string)properties["ConnectionStringSetting"]); Assert.Equal("myPartition", (string)properties["PartitionKey"]); Assert.Equal("myId", (string)properties["Id"]); Assert.Equal(123, (int)properties["CollectionThroughput"]); }
public async Task <IEnumerable <T> > ConvertAsync(DocumentDBAttribute attribute, CancellationToken cancellationToken) { DocumentDBContext 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 DocumentDBUtility.RetryAsync( () => context.Service.ExecuteNextAsync <T>(collectionUri, sqlSpec, continuation), context.MaxThrottleRetries); finalResults.AddRange(response.Results); continuation = response.ResponseContinuation; }while (!string.IsNullOrEmpty(continuation)); return(finalResults); }
internal DocumentClient BindForClient(DocumentDBAttribute attribute) { string resolvedConnectionString = ResolveConnectionString(attribute.ConnectionStringSetting); IDocumentDBService service = GetService(resolvedConnectionString); return(service.GetClient()); }
public static async Task QueueTrigger([QueueTrigger("%WaitTimesUpdatesQueue%")] string myQueueItem, IBinder inputBinder, [DocumentDB("%DocDBDatabase%", "%DocDBCollection%", ConnectionStringSetting = "DocDBConnectionString")] IAsyncCollector <dynamic> collector, TraceWriter log) { log.Info($"Queue trigger function processed a message: {myQueueItem}"); // read the clockwise data var hospitals = await GetWaitsAsync(myQueueItem); // read the urgent care facilities var documentDbAttribute = new DocumentDBAttribute(ConfigurationManager.AppSettings["DocDBDatabase"], ConfigurationManager.AppSettings["DocDBCollection"]) { ConnectionStringSetting = "DocDBConnectionString", SqlQuery = $"SELECT * FROM uc WHERE uc.hospitalId IN ({string.Join(",", hospitals.Select(h => h.HospitalId))}) ORDER BY uc._ts desc" // -- UCOMMENT FOR CASE USING OWN ID --- //SqlQuery = $"SELECT * FROM uc WHERE uc.id IN ({string.Join(",", hospitals.Select(h => $"\"{h.HospitalId}\""))}) ORDER BY uc._ts desc" }; var inputDocuments = await inputBinder.BindAsync <IEnumerable <UrgentCareCenter> >(documentDbAttribute); // update the wait times foreach (var urgentCareFacility in inputDocuments) { var hospital = hospitals.SingleOrDefault(h => h.HospitalId == urgentCareFacility.HospitalId); // -- UCOMMENT FOR CASE USING OWN ID --- //var hospital = hospitals.SingleOrDefault(h => h.HospitalId == int.Parse(urgentCareFacility.Id)); urgentCareFacility.CurrentWaitRangeHigh = hospital.CurrentWaitRangeHigh; urgentCareFacility.CurrentWaitRangeLow = hospital.CurrentWaitRangeLow; await collector.AddAsync(urgentCareFacility); } }
public void CreateContext_AttributeUri_Wins(string attributeConnection, string expectedConnection) { // Arrange var attribute = new DocumentDBAttribute { ConnectionString = attributeConnection }; var mockFactory = new Mock <IDocumentDBServiceFactory>(); mockFactory .Setup(f => f.CreateService(expectedConnection)) .Returns <IDocumentDBService>(null); // Default ConnecitonString will come from app.config var config = new DocumentDBConfiguration { DocumentDBServiceFactory = mockFactory.Object }; // Act DocumentDBAttributeBindingProvider.CreateContext(config, attribute, null); // Assert mockFactory.VerifyAll(); }
internal object BindForOutput(DocumentDBAttribute attribute, Type parameterType, TraceWriter trace) { DocumentDBContext context = CreateContext(attribute, trace); Type collectorType = typeof(DocumentDBAsyncCollector <>).MakeGenericType(parameterType); return(Activator.CreateInstance(collectorType, context)); }
internal Task <IValueBinder> BindForItemAsync(DocumentDBAttribute attribute, Type type, TraceWriter trace) { DocumentDBContext context = CreateContext(attribute, trace); Type genericType = typeof(DocumentDBItemValueBinder <>).MakeGenericType(type); IValueBinder binder = (IValueBinder)Activator.CreateInstance(genericType, context); return(Task.FromResult(binder)); }
public async Task <IBinding> TryCreateAsync(BindingProviderContext context) { if (context == null) { throw new ArgumentNullException("context"); } ParameterInfo parameter = context.Parameter; DocumentDBAttribute attribute = parameter.GetCustomAttribute <DocumentDBAttribute>(inherit: false); if (attribute == null) { return(null); } if (string.IsNullOrEmpty(_docDBConfig.ConnectionString) && string.IsNullOrEmpty(attribute.ConnectionString)) { throw new InvalidOperationException( string.Format(CultureInfo.CurrentCulture, "The DocumentDB connection string must be set either via a '{0}' app setting, via the DocumentDBAttribute.ConnectionString property or via DocumentDBConfiguration.ConnectionString.", DocumentDBConfiguration.AzureWebJobsDocumentDBConnectionStringName)); } DocumentDBContext documentDBContext = CreateContext(_docDBConfig, attribute, _jobHostConfig.NameResolver); if (attribute.CreateIfNotExists) { await CreateIfNotExistAsync(documentDBContext.Service, documentDBContext.ResolvedDatabaseName, documentDBContext.ResolvedCollectionName); } Type coreType = TypeUtility.GetCoreType(parameter.ParameterType); IBinding binding = null; try { binding = BindingFactory.BindGenericCollector(parameter, typeof(DocumentDBAsyncCollector <>), coreType, _jobHostConfig.GetService <IConverterManager>(), (s) => documentDBContext); } catch (Exception ex) { // BindingFactory uses a couple levels of reflection so we get TargetInvocationExceptions here. // This pulls out the root exception and rethrows it. while (ex.InnerException != null) { ex = ex.InnerException; } ExceptionDispatchInfo.Capture(ex).Throw(); } return(binding); }
internal void ValidateConnection(DocumentDBAttribute attribute, Type paramType) { if (string.IsNullOrEmpty(ConnectionString) && string.IsNullOrEmpty(attribute.ConnectionString)) { throw new InvalidOperationException( string.Format(CultureInfo.CurrentCulture, "The DocumentDB connection string must be set either via a '{0}' app setting, via the DocumentDBAttribute.ConnectionString property or via DocumentDBConfiguration.ConnectionString.", AzureWebJobsDocumentDBConnectionStringName)); } }
public void CreateContext_UsesDefaultRetryValue() { // Arrange var attribute = new DocumentDBAttribute(); var config = new DocumentDBConfiguration(); // Act var context = config.CreateContext(attribute, new TestTraceWriter()); // Assert Assert.Equal(DocumentDBContext.DefaultMaxThrottleRetries, context.MaxThrottleRetries); }
public void MethodsWithDisabledParametersShouldBeDisabled() { var attribute = new DocumentDBAttribute() { ConnectionStringSetting = "value" }; var jObject = attribute.ToJObject(); jObject.Should().HaveElement("connection"); jObject["connection"].Should().Be("value"); }
internal DocumentDBContext CreateContext(DocumentDBAttribute attribute, TraceWriter trace) { string resolvedConnectionString = ResolveConnectionString(attribute.ConnectionStringSetting); IDocumentDBService service = GetService(resolvedConnectionString); return(new DocumentDBContext { Service = service, Trace = trace, ResolvedAttribute = attribute }); }
internal Task <IValueBinder> BindForItemAsync(DocumentDBAttribute attribute, Type type) { if (string.IsNullOrEmpty(attribute.Id)) { throw new InvalidOperationException("The 'Id' property of a DocumentDB single-item input binding cannot be null or empty."); } DocumentDBContext context = CreateContext(attribute); Type genericType = typeof(DocumentDBItemValueBinder <>).MakeGenericType(type); IValueBinder binder = (IValueBinder)Activator.CreateInstance(genericType, context); return(Task.FromResult(binder)); }
public void CreateContext_UsesDefaultRetryValue() { // Arrange var attribute = new DocumentDBAttribute { ConnectionStringSetting = "AccountEndpoint=https://someuri;AccountKey=c29tZV9rZXk=;" }; var config = new DocumentDBConfiguration(); // Act var context = config.CreateContext(attribute); // Assert Assert.Equal(DocumentDBContext.DefaultMaxThrottleRetries, context.MaxThrottleRetries); }
private static DocumentDBContext CreateContext(IDocumentDBService service, bool createIfNotExists = false, string partitionKeyPath = null, int throughput = 0) { DocumentDBAttribute attribute = new DocumentDBAttribute(DatabaseName, CollectionName) { CreateIfNotExists = createIfNotExists, PartitionKey = partitionKeyPath, CollectionThroughput = throughput }; return(new DocumentDBContext { Service = service, ResolvedAttribute = attribute }); }
public async Task Configuration_Caches_Clients() { // Arrange var config = new DocumentDBConfiguration { ConnectionString = "AccountEndpoint=https://someuri;AccountKey=some_key", }; var attribute = new DocumentDBAttribute(); // Act var client = config.BindForClient(attribute); var context = config.BindForOutput(attribute, typeof(Item), null); var binder = await config.BindForItemAsync(attribute, typeof(Item), null); // Assert Assert.Equal(1, config.ClientCache.Count); }
public async Task Configuration_Caches_Clients() { // Arrange var config = new DocumentDBConfiguration { ConnectionString = "AccountEndpoint=https://someuri;AccountKey=c29tZV9rZXk=;", }; var attribute = new DocumentDBAttribute(); // Act var context1 = config.CreateContext(attribute); var context2 = config.CreateContext(attribute); var binder = await config.BindForItemAsync(attribute, typeof(Item)); // Assert Assert.Equal(1, config.ClientCache.Count); }
private static DocumentDBItemValueBinder <T> CreateBinder <T>(out Mock <IDocumentDBService> mockService, string partitionKey = null) where T : class { mockService = new Mock <IDocumentDBService>(MockBehavior.Strict); DocumentDBAttribute attribute = new DocumentDBAttribute(DatabaseName, CollectionName) { Id = Id, PartitionKey = partitionKey }; var context = new DocumentDBContext { ResolvedAttribute = attribute, Service = mockService.Object }; return(new DocumentDBItemValueBinder <T>(context)); }
public override Collection <Attribute> GetAttributes() { Collection <Attribute> attributes = new Collection <Attribute>(); string databaseName = Context.GetMetadataValue <string>("databaseName"); string collectionName = Context.GetMetadataValue <string>("collectionName"); if (Context.IsTrigger) { CosmosDBTriggerAttribute attributeTrigger = new CosmosDBTriggerAttribute(databaseName, collectionName); attributeTrigger.ConnectionStringSetting = Context.GetMetadataValue <string>("connectionStringSetting"); attributeTrigger.LeaseDatabaseName = Context.GetMetadataValue <string>("leaseDatabaseName"); attributeTrigger.LeaseCollectionName = Context.GetMetadataValue <string>("leaseCollectionName"); attributeTrigger.LeaseConnectionStringSetting = Context.GetMetadataValue <string>("leaseConnectionStringSetting"); attributeTrigger.CreateLeaseCollectionIfNotExists = Context.GetMetadataValue <bool>("createLeaseCollectionIfNotExists", false); attributeTrigger.LeasesCollectionThroughput = Context.GetMetadataValue <int>("leaseCollectionThroughput", 0); attributes.Add(attributeTrigger); } else { DocumentDBAttribute attribute = null; if (!string.IsNullOrEmpty(databaseName) || !string.IsNullOrEmpty(collectionName)) { attribute = new DocumentDBAttribute(databaseName, collectionName); } else { attribute = new DocumentDBAttribute(); } attribute.CreateIfNotExists = Context.GetMetadataValue <bool>("createIfNotExists"); attribute.ConnectionStringSetting = Context.GetMetadataValue <string>("connection"); attribute.Id = Id; attribute.PartitionKey = Context.GetMetadataValue <string>("partitionKey"); attribute.CollectionThroughput = Context.GetMetadataValue <int>("collectionThroughput"); attribute.SqlQuery = Context.GetMetadataValue <string>("sqlQuery"); attributes.Add(attribute); } return(attributes); }
public void TemplateBind_DuplicateParameters() { // Arrange PropertyInfo propInfo = null; DocumentDBAttribute resolvedAttribute = new DocumentDBAttribute(); 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"); DocumentDBSqlResolutionPolicy policy = new DocumentDBSqlResolutionPolicy(); // 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 CreateIfNotExists_DoesNotCreate_IfFalse() { // Arrange var mockService = new Mock <IDocumentDBService>(MockBehavior.Strict); var config = new DocumentDBConfiguration { ConnectionString = "AccountEndpoint=http://someuri;AccountKey=some_key", DocumentDBServiceFactory = new TestDocumentDBServiceFactory(mockService.Object) }; var attribute = new DocumentDBAttribute { CreateIfNotExists = false }; var provider = new DocumentDBAttributeBindingProvider(new JobHostConfiguration(), config); // Act await provider.TryCreateAsync(new BindingProviderContext(GetCreateIfNotExistsParameters().First(), null, CancellationToken.None)); // Assert // Nothing to assert. Since the service was null, it was never called. }
public async Task ConvertAsync_Succeeds_WithContinuation() { Mock <IDocumentDBService> mockService; var builder = CreateBuilder <Document>(out 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 }); DocumentDBAttribute attribute = new DocumentDBAttribute(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 ConvertAsync_RethrowsException_IfNotFound() { Mock <IDocumentDBService> mockService; var builder = CreateBuilder <Item>(out mockService); mockService .Setup(m => m.ExecuteNextAsync <Item>(_expectedUri, It.IsAny <SqlQuerySpec>(), It.IsAny <string>())) .ThrowsAsync(DocumentDBTestUtility.CreateDocumentClientException((HttpStatusCode)404)); DocumentDBAttribute attribute = new DocumentDBAttribute(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 override async Task BindAsync(BindingContext context) { DocumentDBAttribute attribute = new DocumentDBAttribute(DatabaseName, CollectionName) { CreateIfNotExists = CreateIfNotExists, ConnectionString = ConnectionString, Id = Id, PartitionKey = PartitionKey, CollectionThroughput = CollectionThroughput }; RuntimeBindingContext runtimeContext = new RuntimeBindingContext(attribute); if (Access == FileAccess.Read && _bindingDirection == BindingDirection.In) { context.Value = await context.Binder.BindAsync <JObject>(runtimeContext); } else if (Access == FileAccess.Write && _bindingDirection == BindingDirection.Out) { await BindAsyncCollectorAsync <JObject>(context, runtimeContext); } }
public async Task SetAsync_Updates_IfPropertyChanges() { // Arrange var mockService = new Mock <IDocumentDBService>(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()); DocumentDBAttribute attribute = new DocumentDBAttribute(DatabaseName, CollectionName) { Id = Id }; var context = new DocumentDBContext { Service = mockService.Object, ResolvedAttribute = attribute }; JObject clonedOrig = DocumentDBItemValueBinder <object> .CloneItem(original); // Act await DocumentDBItemValueBinder <Item> .SetValueInternalAsync(clonedOrig, updated, context); // Assert mockService.VerifyAll(); }
internal static void ValidateInputBinding(DocumentDBAttribute 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(DocumentDBAttribute.Id)}' can be specified."); } if (IsSupportedEnumerable(parameterType)) { if (hasId) { throw new InvalidOperationException($"'{nameof(DocumentDBAttribute.Id)}' cannot be specified when binding to an IEnumerable property."); } } else if (!hasId) { throw new InvalidOperationException($"'{nameof(DocumentDBAttribute.Id)}' is required when binding to a {parameterType.Name} property."); } }
public void CreateContext_ResolvesNames() { // Arrange var resolver = new TestNameResolver(); resolver.Values.Add("MyDatabase", "123abc"); resolver.Values.Add("MyCollection", "abc123"); var attribute = new DocumentDBAttribute("%MyDatabase%", "%MyCollection%"); var config = new DocumentDBConfiguration { ConnectionString = "AccountEndpoint=https://someuri;AccountKey=some_key" }; // Act var context = DocumentDBAttributeBindingProvider.CreateContext(config, attribute, resolver); // Assert Assert.Equal("123abc", context.ResolvedDatabaseName); Assert.Equal("abc123", context.ResolvedCollectionName); }
public async Task SetAsync_Poco_SkipsUpdate_IfSame() { // Arrange var mockService = new Mock <IDocumentDBService>(MockBehavior.Strict); Item original = new Item { Id = "abc123", Text = "hello" }; Item updated = new Item { Id = "abc123", Text = "hello" }; DocumentDBAttribute attribute = new DocumentDBAttribute(DatabaseName, CollectionName) { Id = Id }; var context = new DocumentDBContext { Service = mockService.Object, ResolvedAttribute = attribute }; JObject clonedOrig = DocumentDBItemValueBinder <object> .CloneItem(original); // Act await DocumentDBItemValueBinder <Item> .SetValueInternalAsync(clonedOrig, updated, context); // Assert // nothing on the client should be called mockService.VerifyAll(); }
public override async Task BindAsync(BindingContext context) { DocumentDBAttribute attribute = new DocumentDBAttribute(DatabaseName, CollectionName) { CreateIfNotExists = CreateIfNotExists, ConnectionString = ConnectionString, Id = Id }; RuntimeBindingContext runtimeContext = new RuntimeBindingContext(attribute); if (Access == FileAccess.Read && _bindingDirection == BindingDirection.In) { JObject input = await context.Binder.BindAsync<JObject>(runtimeContext); if (input != null) { byte[] byteArray = Encoding.UTF8.GetBytes(input.ToString()); using (MemoryStream stream = new MemoryStream(byteArray)) { stream.CopyTo(context.Value); } } } else if (Access == FileAccess.Write && _bindingDirection == BindingDirection.Out) { await BindAsyncCollectorAsync<JObject>(context.Value, context.Binder, runtimeContext); } }