private static HistoryEvent ToHistoryEvent(this HistoryEntity evt,
                                            DateTimeOffset?scheduledTime = null,
                                            string functionName          = null,
                                            string eventType             = null,
                                            string subOrchestrationId    = null)
 {
     return(new HistoryEvent
     {
         Timestamp = evt._Timestamp.ToUniversalTime(),
         EventType = eventType ?? evt.EventType,
         EventId = evt.TaskScheduledId,
         Name = string.IsNullOrEmpty(evt.Name) ? functionName : evt.Name,
         Result = evt.Result,
         Details = evt.Details,
         SubOrchestrationId = subOrchestrationId,
         ScheduledTime = scheduledTime,
         DurationInMs = scheduledTime.HasValue ? (evt._Timestamp - scheduledTime.Value).TotalMilliseconds : 0
     });
 }
        /// <summary>
        /// Fetches orchestration instance history directly from XXXHistory table
        /// Tries to mimic this algorithm: https://github.com/Azure/azure-functions-durable-extension/blob/main/src/WebJobs.Extensions.DurableTask/ContextImplementations/DurableClient.cs#L718
        /// Intentionally returns IEnumerable<>, because the consuming code not always iterates through all of it.
        /// </summary>
        public static IEnumerable <HistoryEvent> GetHistoryDirectlyFromTable(IDurableClient durableClient, string connName, string hubName, string instanceId)
        {
            var tableClient = TableClient.GetTableClient(connName);

            // Need to fetch executionId first

            var instanceEntity = tableClient.ExecuteAsync($"{hubName}Instances", TableOperation.Retrieve(instanceId, string.Empty))
                                 .Result.Result as DynamicTableEntity;

            string executionId = instanceEntity.Properties.ContainsKey("ExecutionId") ?
                                 instanceEntity.Properties["ExecutionId"].StringValue :
                                 null;

            var instanceIdFilter = TableQuery.CombineFilters
                                   (
                TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, instanceId),
                TableOperators.And,
                TableQuery.GenerateFilterCondition("ExecutionId", QueryComparisons.Equal, executionId)
                                   );

            // Fetching _all_ correlated events with a separate parallel query. This seems to be the only option.
            var correlatedEventsQuery = new TableQuery <HistoryEntity>().Where
                                        (
                TableQuery.CombineFilters
                (
                    instanceIdFilter,
                    TableOperators.And,
                    TableQuery.GenerateFilterConditionForInt("TaskScheduledId", QueryComparisons.GreaterThanOrEqual, 0)
                )
                                        );

            var correlatedEventsTask = tableClient.GetAllAsync($"{hubName}History", correlatedEventsQuery)
                                       .ContinueWith(t => t.Result.ToDictionary(e => e.TaskScheduledId));

            // Memorizing 'ExecutionStarted' event, to further correlate with 'ExecutionCompleted'
            HistoryEntity executionStartedEvent = null;

            // Fetching the history
            var query = new TableQuery <HistoryEntity>().Where(instanceIdFilter);

            foreach (var evt in tableClient.GetAll($"{hubName}History", query))
            {
                switch (evt.EventType)
                {
                case "TaskScheduled":
                case "SubOrchestrationInstanceCreated":

                    // Trying to match the completion event
                    correlatedEventsTask.Result.TryGetValue(evt.EventId, out var correlatedEvt);
                    if (correlatedEvt != null)
                    {
                        yield return(correlatedEvt.ToHistoryEvent
                                     (
                                         evt._Timestamp,
                                         evt.Name,
                                         correlatedEvt.EventType == "GenericEvent" ? evt.EventType : null,
                                         evt.InstanceId
                                     ));
                    }
                    else
                    {
                        yield return(evt.ToHistoryEvent());
                    }

                    break;

                case "ExecutionStarted":

                    executionStartedEvent = evt;

                    yield return(evt.ToHistoryEvent(null, evt.Name));

                    break;

                case "ExecutionCompleted":
                case "ExecutionFailed":
                case "ExecutionTerminated":

                    yield return(evt.ToHistoryEvent(executionStartedEvent?._Timestamp));

                    break;

                case "ContinueAsNew":
                case "TimerCreated":
                case "TimerFired":
                case "EventRaised":
                case "EventSent":

                    yield return(evt.ToHistoryEvent());

                    break;
                }
            }
        }