public async void Run([CosmosDBTrigger(
                                   databaseName: "Tasks",
                                   collectionName: "TaskItem",
                                   ConnectionStringSetting = "CosmosDBConnection",
                                   LeaseCollectionName = "leases",
                                   CreateLeaseCollectionIfNotExists = true)] IReadOnlyList <Document> input,
                              //CosmosNote - For V2 SDK, we can use the cosmos binding to get a handle to the DocumentClient object.  This is different than
                              //V3 SDK where we use dependency injection to get the handle and abstract it from the function.
                              [CosmosDB(
                                   databaseName: "Tasks",
                                   collectionName: "TaskViews",
                                   ConnectionStringSetting = "CosmosDBConnection")] DocumentClient _cosmosClient,
                              ExecutionContext context,
                              ILogger log)
        {
            //CosmosNote - in our v2 code example, we get the DocumentClient from the binding.  Thus, we instantiate
            //the CosmosHelper here and pass in the handle to the client.  In the v3 example, the CosmosClient is
            //created when the singleton object is instantiated in Startup.cs.
            CosmosHelper cosmosHelper = new CosmosHelper(_cosmosClient);

            //Loop through all the v2 Documents we receive in the change feed.
            if (input != null && input.Count > 0)
            {
                log.LogInformation("Documents modified " + input.Count);

                foreach (Document document in input)
                {
                    //Convert the document into a dynamic object so we can work with it without binding to a model.
                    dynamic task = JsonConvert.DeserializeObject <ExpandoObject>(document.ToString(), new ExpandoObjectConverter());

                    //Get the TaskItemView for this submitter and update it accordingly.  If there is an etag discrepancy, we'll get a false back and need to try again.
                    bool taskOwnerViewResult = false;
                    while (taskOwnerViewResult == false)
                    {
                        dynamic taskOwnerView = await getTaskView(cosmosHelper, task.submittedby, log);

                        handleTaskApprovals(task, taskOwnerView, log);
                        taskOwnerViewResult = await saveTaskView(cosmosHelper, taskOwnerView, log);
                    }

                    //Loop through all the approvers in the document and update them.  If there is an etag discrepancy, we'll get a false back and need to try again.
                    foreach (dynamic approver in task.approvers)
                    {
                        bool taskApproverResult = false;
                        while (taskApproverResult == false)
                        {
                            dynamic taskApproverView = await getTaskView(cosmosHelper, approver.id, log);

                            handleTaskApprovals(task, taskApproverView, log);
                            taskApproverResult = await saveTaskView(cosmosHelper, taskApproverView, log);
                        }
                    }
                }
            }
        }
 private async System.Threading.Tasks.Task <bool> saveTaskView(CosmosHelper _cosmosHelper, dynamic taskView, ILogger log)
 {
     //If they still have tasks to approve, go ahead and upsert the document.  Otherwise, delete it for good housekeeping.
     if ((taskView.mytasks.Count > 0) || (taskView.approvaltasks.Count > 0))
     {
         return(await _cosmosHelper.UpsertItemAsync("Tasks", "TaskViews", taskView, true, log));
     }
     else
     {
         return(await _cosmosHelper.DeleteItemAsync("Tasks", "TaskViews", taskView, true, log));
     }
 }
        public override void Configure(IFunctionsHostBuilder builder)
        {
            // Register the CosmosHelper as a Singleton
            builder.Services.AddSingleton((s) => {
                string connectionString = configuration["CosmosDBConnection"];
                if (string.IsNullOrEmpty(connectionString))
                {
                    throw new ArgumentNullException("Please specify a valid CosmosDBConnection in the appSettings.json file or your Azure Functions Settings.");
                }

                CosmosHelper cosmosHelper = new CosmosHelper(connectionString);
                return(cosmosHelper);
            });
        }
        private async Task <dynamic> getTaskView(CosmosHelper _cosmosHelper, dynamic id, ILogger log)
        {
            dynamic taskView = null;

            //Use the CosmosHelper to get the TaskView.
            dynamic document = await _cosmosHelper.ReadItemAsync("Tasks", "TaskViews", id, log);

            if (document != null)
            {
                taskView = JsonConvert.DeserializeObject <ExpandoObject>(document.ToString(), new ExpandoObjectConverter());
            }
            else
            {
                log.LogInformation($"User {id} does not have a TaskItemView.  A new document will be created.");
                taskView               = new ExpandoObject();
                taskView.id            = id;
                taskView.mytasks       = new List <ExpandoObject>();
                taskView.approvaltasks = new List <ExpandoObject>();
            }
            return(taskView);
        }
 //CosmosNote - In order to easily get the CosmosHelper to read and update Tasks, we use dependency injection.  This is different from V2 where we can use
 //the Cosmos function binding to get the DocumentClient, and then build the CosmosHelper.
 public TaskUpdateChangeFeedFunction(CosmosHelper cosmosHelper)
 {
     //Get the cosmos client object that our Startup.cs creates through dependency injection.
     _cosmosHelper = cosmosHelper;
 }
 //CosmosNote - In order to easily get the CosmosHelper to read and update Tasks, we use dependency injection.  This is different from V2 where we can use
 //the Cosmos function binding to get the DocumentClient, and then build the CosmosHelper.
 public GetTaskViewFunction(CosmosHelper cosmosHelper)
 {
     //Get the cosmos client object that our Startup.cs creates through dependency injection.
     _cosmosHelper = cosmosHelper;
 }