public static async Task <IEnumerable <TResult> > QueryAsync <TElement, TResult>(
            this CloudTable table,
            TableQuery <TElement> query,
            EntityResolver <TResult> entityResolver,
            CancellationToken cancellationToken  = default,
            Action <IList <TResult> > onProgress = null)
            where TElement : class, ITableEntity, new()
            where TResult : class, ITableEntity, new()
        {
            if (query == null)
            {
                throw new ArgumentNullException(nameof(query));
            }

            var items = new List <TResult>();
            TableContinuationToken continuationToken = null;

            do
            {
                TableQuerySegment <TResult> segment = await table.ExecuteInternalAsync(
                    async t => await t.ExecuteQuerySegmentedAsync(query, entityResolver, continuationToken, cancellationToken));

                continuationToken = segment.ContinuationToken;
                items.AddRange(segment);
                onProgress?.Invoke(items);
            } while (continuationToken != null && !cancellationToken.IsCancellationRequested);

            return(items);
        }
        private static async Task BatchExecuteAsync(this CloudTable table, IEnumerable <ITableEntity> items, Action <TableBatchOperation, ITableEntity> batchAction)
        {
            var itemsGroupedByPartition = items.GroupBy(x => x.PartitionKey);
            var tasks = new List <Task>();

            foreach (var itemPartitionGroup in itemsGroupedByPartition)
            {
                int itemPartitionGroupCount = itemPartitionGroup.Count();
                for (int i = 0; i < itemPartitionGroupCount; i += Constants.TableServiceBatchMaximumOperations)
                {
                    var batch      = new TableBatchOperation();
                    var batchItems = itemPartitionGroup.Skip(i).Take(Constants.TableServiceBatchMaximumOperations).ToList();

                    foreach (var item in batchItems)
                    {
                        batchAction(batch, item);
                    }

                    var task = table.ExecuteInternalAsync(batch);
                    tasks.Add(task);

                    if (tasks.Count >= Constants.DefaultMaxConcurrentBatchOperations)
                    {
                        await Task.WhenAll(tasks);

                        tasks.Clear();
                    }
                }
            }

            await Task.WhenAll(tasks);
        }
        private static async Task <T> ExecuteInternalAsync <T>(this CloudTable table, Func <CloudTable, Task <T> > action, bool isRetry = false)
        {
            try
            {
                return(await action(table));
            }
            catch (StorageException ex) when(ex.RequestInformation?.ExtendedErrorInformation?.ErrorCode == ErrorCodes.TableNotFound)
            {
                if (isRetry)
                {
                    throw;
                }

                await table.CreateIfNotExistsAsync();

                return(await table.ExecuteInternalAsync(action, isRetry : true));
            }
        }
 public static async Task <TableResult> InsertOrReplaceAsync(this CloudTable table, ITableEntity entity)
 => await table.ExecuteInternalAsync(TableOperation.InsertOrReplace(entity));
 private static async Task <TableBatchResult> ExecuteInternalAsync(this CloudTable table, TableBatchOperation operation, bool isRetry = false)
 => await table.ExecuteInternalAsync(async t => await t.ExecuteBatchAsync(operation), isRetry);
 public static async Task DeleteAsync(this CloudTable table, ITableEntity entity)
 => await table.ExecuteInternalAsync(TableOperation.Delete(entity));