Пример #1
0
        public Task <Func <Task> > CascadeDeleteAsync <TEntity>(MemberInfo memberInfo,
                                                                string rowKeyRef, string partitionKeyRef,
                                                                TEntity memberValue, IDictionary <string, EntityProperty> dictionary,
                                                                AzureTableDriverDynamic repository)
        {
            var tableName = GetLookupTableName(memberInfo);

            return(repository
                   .DeleteAsync <StorageLookupTable, Func <Task> >(rowKeyRef, partitionKeyRef,
                                                                   async(lookupTable, deleteAsync) =>
            {
                var lookupEntity = await deleteAsync();
                var rollbacks = await lookupTable
                                .rowAndPartitionKeys
                                .NullToEmpty()
                                .Select(rowParitionKeyKvp =>
                                        repository.DeleteAsync <Func <Task> >(rowParitionKeyKvp.Key, rowParitionKeyKvp.Value, memberInfo.DeclaringType,
                                                                              (entity, data) =>
                                                                              () => (Task)repository.CreateAsync(entity, memberInfo.DeclaringType,
                                                                                                                 (x) => true, () => false),
                                                                              () =>
                                                                              () => 1.AsTask()))
                                .AsyncEnumerable()
                                .Append(
                    () => repository.CreateAsync(lookupEntity, tableName,
                                                 x => true,
                                                 () => false))
                                .ToArrayAsync();
                Func <Task> rollbacksAll = () => Task.WhenAll(rollbacks.Select(rollback => rollback()));
                return rollbacksAll;
            },
                                                                   () => () => 0.AsTask(),
                                                                   tableName: tableName));
        }
Пример #2
0
        public Task <TResult> ExecuteUpdateAsync <TEntity, TResult>(MemberInfo memberInfo,
                                                                    string rowKey, string partitionKey,
                                                                    TEntity valueExisting, IDictionary <string, EntityProperty> dictionaryExisting,
                                                                    TEntity valueUpdated, IDictionary <string, EntityProperty> dictionaryUpdated,
                                                                    AzureTableDriverDynamic repository,
                                                                    Func <Func <Task>, TResult> onSuccessWithRollback,
                                                                    Func <TResult> onFailure)
        {
            var to             = (IModifyAzureStorageTablePartitionKey)Activator.CreateInstance(this.To);
            var toPartitionKey = to.GeneratePartitionKey(rowKey, valueUpdated, memberInfo);
            var typeWrapper    = new TypeWrapper(rowKey, toPartitionKey, dictionaryUpdated);

            return(repository.InsertOrReplaceAsync <TEntity, TResult>(typeWrapper,
                                                                      (created, newEntity) => onSuccessWithRollback(
                                                                          () =>
            {
                if (created)
                {
                    return repository.DeleteAsync <TEntity, bool>(newEntity,
                                                                  () => true,
                                                                  () => true);
                }
                var typeWrapperExisting = new TypeWrapper(rowKey, toPartitionKey, dictionaryExisting);
                return repository.ReplaceAsync <TEntity, bool>(typeWrapperExisting,
                                                               () => true);
            })));
        }
        public async Task <TResult> ExecuteDeleteAsync <TEntity, TResult>(MemberInfo memberInfo,
                                                                          string rowKeyRef, string partitionKeyRef,
                                                                          TEntity value, IDictionary <string, EntityProperty> dictionary,
                                                                          AzureTableDriverDynamic repository,
                                                                          Func <Func <Task>, TResult> onSuccessWithRollback,
                                                                          Func <TResult> onFailure)
        {
            if (IsIgnored(memberInfo, value))
            {
                return(onSuccessWithRollback(() => true.AsTask()));
            }

            var hashRowKey       = GetHashRowKey(memberInfo, value, out string discard);
            var hashPartitionKey = memberInfo.DeclaringType.Name;
            var tableName        = GetLookupTableName(memberInfo);

            return(await repository.DeleteAsync <StorageLookupTable, TResult>(
                       hashRowKey, hashPartitionKey,
                       async (entity, deleteAsync) =>
            {
                await deleteAsync();
                return onSuccessWithRollback(
                    () => repository.CreateAsync(entity,
                                                 (discardAgain, discard2x) => true, () => false));
            },
                       () => onSuccessWithRollback(() => 1.AsTask()),
                       (codes, why) => onSuccessWithRollback(() => 1.AsTask()),
                       tableName : tableName));
        }
Пример #4
0
        public Task <TResult> ExecuteUpdateAsync <TEntity, TResult>(MemberInfo memberInfo,
                                                                    IAzureStorageTableEntity <TEntity> updatedEntity,
                                                                    IAzureStorageTableEntity <TEntity> existingEntity,
                                                                    AzureTableDriverDynamic repository,
                                                                    Func <Func <Task>, TResult> onSuccessWithRollback,
                                                                    Func <TResult> onFailure)
        {
            var rowKey            = updatedEntity.RowKey;
            var valueUpdated      = updatedEntity.Entity;
            var dictionaryUpdated = updatedEntity.WriteEntity(null);
            var to                 = (IModifyAzureStorageTablePartitionKey)Activator.CreateInstance(this.To);
            var toPartitionKey     = to.GeneratePartitionKey(rowKey, valueUpdated, memberInfo);
            var typeWrapper        = new TypeWrapper(rowKey, toPartitionKey, dictionaryUpdated);
            var dictionaryExisting = existingEntity.WriteEntity(null);

            return(repository.InsertOrReplaceAsync <TEntity, TResult>(typeWrapper,
                                                                      (created, newEntity) => onSuccessWithRollback(
                                                                          () =>
            {
                if (created)
                {
                    return repository.DeleteAsync <TEntity, bool>(newEntity,
                                                                  () => true,
                                                                  () => true,
                                                                  () => false,
                                                                  (codes, why) => false);
                }
                var typeWrapperExisting = new TypeWrapper(rowKey, toPartitionKey, dictionaryExisting);
                return repository.ReplaceAsync <TEntity, bool>(typeWrapperExisting,
                                                               () => true);
            })));
        }
        public async Task <TResult> ExecuteInsertOrReplaceAsync <TEntity, TResult>(MemberInfo memberInfo,
                                                                                   string rowKeyRef, string partitionKeyRef,
                                                                                   TEntity value, IDictionary <string, EntityProperty> dictionary,
                                                                                   AzureTableDriverDynamic repository,
                                                                                   Func <Func <Task>, TResult> onSuccessWithRollback,
                                                                                   Func <TResult> onFailure)
        {
            if (IsIgnored(memberInfo, value))
            {
                return(onSuccessWithRollback(() => true.AsTask()));
            }
            var hashRowKey       = GetHashRowKey(memberInfo, value, out string[] hashKeys);
            var hashPartitionKey = memberInfo.DeclaringType.Name;
            var tableName        = GetLookupTableName(memberInfo);

            return(await repository.UpdateOrCreateAsync <StorageLookupTable, TResult>(
                       hashRowKey, hashPartitionKey,
                       async (created, lookup, saveAsync) =>
            {
                bool ClaimedByDifferentResource()
                {
                    if (created)
                    {
                        return false;
                    }

                    if (lookup.rowKeyRef != rowKeyRef)
                    {
                        return true;
                    }

                    if (lookup.partitionKeyRef != partitionKeyRef)
                    {
                        return true;
                    }

                    return false;
                }

                if (ClaimedByDifferentResource())
                {
                    return onFailure();
                }

                lookup.rowKeyRef = rowKeyRef;
                lookup.partitionKeyRef = partitionKeyRef;
                lookup.hashvalues = hashKeys;
                await saveAsync(lookup);
                Func <Task <bool> > rollback =
                    async() =>
                {
                    return await repository.DeleteAsync <StorageLookupTable, bool>(hashRowKey, hashPartitionKey,
                                                                                   () => true,
                                                                                   () => false,
                                                                                   tableName: tableName);
                };
                return onSuccessWithRollback(rollback);
            },
                       tableName : tableName));
        }
Пример #6
0
        public virtual Task <TResult> ExecuteCreateAsync <TEntity, TResult>(MemberInfo memberInfo,
                                                                            string rowKey, string partitionKey,
                                                                            TEntity value, IDictionary <string, EntityProperty> dictionary,
                                                                            AzureTableDriverDynamic repository,
                                                                            Func <Func <Task>, TResult> onSuccessWithRollback,
                                                                            Func <TResult> onFailure)
        {
            var to             = (IModifyAzureStorageTablePartitionKey)Activator.CreateInstance(this.To);
            var toPartitionKey = to.GeneratePartitionKey(rowKey, value, memberInfo);
            var typeWrapper    = new TypeWrapper(rowKey, toPartitionKey, dictionary);

            return(repository.CreateAsync <TEntity, TResult>(typeWrapper,
                                                             (entity) => onSuccessWithRollback(
                                                                 () => repository.DeleteAsync <TEntity, bool>(entity,
                                                                                                              () => true,
                                                                                                              () => true)),
                                                             () => onSuccessWithRollback(() => false.AsTask())));
        }
Пример #7
0
        public Task <TResult> ExecuteDeleteAsync <TEntity, TResult>(MemberInfo memberInfo,
                                                                    string rowKey, string partitionKey,
                                                                    TEntity value, IDictionary <string, EntityProperty> dictionary,
                                                                    AzureTableDriverDynamic repository,
                                                                    Func <Func <Task>, TResult> onSuccessWithRollback,
                                                                    Func <TResult> onFailure)
        {
            var to             = (IModifyAzureStorageTablePartitionKey)Activator.CreateInstance(this.To);
            var toPartitionKey = to.GeneratePartitionKey(rowKey, value, memberInfo);
            var typeWrapper    = new TypeWrapper(rowKey, toPartitionKey, dictionary);

            return(repository.DeleteAsync <TEntity, TResult>(typeWrapper,
                                                             () => onSuccessWithRollback(
                                                                 () =>
            {
                return repository.CreateAsync <TEntity, bool>(typeWrapper,
                                                              (createdEntity) => true,
                                                              () => true);
            }),
                                                             () => onSuccessWithRollback(
                                                                 () => 1.AsTask()),
                                                             () => throw new Exception("Delete with ETAG = * failed due to modification.")));
        }
        public async Task <TResult> ExecuteUpdateAsync <TEntity, TResult>(MemberInfo memberInfo,
                                                                          IAzureStorageTableEntity <TEntity> updatedEntity,
                                                                          IAzureStorageTableEntity <TEntity> existingEntity,
                                                                          AzureTableDriverDynamic repository,
                                                                          Func <Func <Task>, TResult> onSuccessWithRollback,
                                                                          Func <TResult> onFailure)
        {
            var valueExisting        = existingEntity.Entity;
            var existingRowKey       = valueExisting.StorageGetRowKey();
            var existingPartitionKey = valueExisting.StorageGetPartitionKey();

            var valueUpdated       = updatedEntity.Entity;
            var rowKeyRef          = updatedEntity.RowKey;
            var partitionKeyRef    = updatedEntity.PartitionKey;
            var dictionaryExisting = existingEntity.WriteEntity(null);

            if (IsIgnored(memberInfo, valueUpdated))
            {
                if (IsIgnored(memberInfo, valueExisting))
                {
                    return(onSuccessWithRollback(() => true.AsTask()));
                }
                var rollbackMaybeTask = await ExecuteDeleteAsync(memberInfo, rowKeyRef, partitionKeyRef,
                                                                 valueExisting, dictionaryExisting,
                                                                 repository,
                                                                 (rb) => rb,
                                                                 () => default);

                return(onSuccessWithRollback(rollbackMaybeTask));
            }

            var hashRowKey       = GetHashRowKey(memberInfo, valueUpdated, out string hashKeys);
            var hashPartitionKey = memberInfo.DeclaringType.Name;
            var tableName        = GetLookupTableName(memberInfo);

            return(await repository.UpdateOrCreateAsync <StorageLookupTable, TResult>(
                       hashRowKey, hashPartitionKey,
                       async (created, lookup, saveAsync) =>
            {
                if (!created)
                {
                    return onFailure();
                }

                async Task <Func <Task> > RollbackMaybeAsync()
                {
                    if (IsIgnored(memberInfo, valueExisting))
                    {
                        return default(Func <Task>);
                    }
                    return await ExecuteDeleteAsync(memberInfo, rowKeyRef, partitionKeyRef,
                                                    valueExisting, dictionaryExisting,
                                                    repository,
                                                    (rb) => rb,
                                                    () => default);
                }

                var rollbackMaybeTask = RollbackMaybeAsync();
                lookup.rawHash = hashKeys;     // Store raw hash to make the table easier to debug
                await saveAsync(lookup);
                var rollbackMaybe = await rollbackMaybeTask;

                Func <Task <bool> > rollback =
                    async() =>
                {
                    if (!rollbackMaybe.IsDefaultOrNull())
                    {
                        await rollbackMaybe();
                    }
                    return await repository.DeleteAsync <StorageLookupTable, bool>(hashRowKey, hashPartitionKey,
                                                                                   (discard) => true,
                                                                                   () => false,
                                                                                   onFailure: (codes, why) => false,
                                                                                   tableName: tableName);
                };
                return onSuccessWithRollback(rollback);
            },
                       tableName : tableName));
        }
        public async Task <TResult> ExecuteUpdateAsync <TEntity, TResult>(MemberInfo memberInfo,
                                                                          string rowKeyRef, string partitionKeyRef,
                                                                          TEntity valueExisting, IDictionary <string, EntityProperty> dictionaryExisting,
                                                                          TEntity valueUpdated, IDictionary <string, EntityProperty> dictionaryUpdated,
                                                                          AzureTableDriverDynamic repository,
                                                                          Func <Func <Task>, TResult> onSuccessWithRollback,
                                                                          Func <TResult> onFailure)
        {
            var existingRowKey       = valueExisting.StorageGetRowKey();
            var existingPartitionKey = valueExisting.StorageGetPartitionKey();

            if (IsIgnored(memberInfo, valueUpdated))
            {
                if (IsIgnored(memberInfo, valueExisting))
                {
                    return(onSuccessWithRollback(() => true.AsTask()));
                }
                var rollbackMaybeTask = await ExecuteDeleteAsync(memberInfo, rowKeyRef, partitionKeyRef,
                                                                 valueExisting, dictionaryExisting,
                                                                 repository,
                                                                 (rb) => rb,
                                                                 () => default);

                return(onSuccessWithRollback(rollbackMaybeTask));
            }

            var hashRowKey       = GetHashRowKey(memberInfo, valueUpdated, out string[] hashKeys);
            var hashPartitionKey = memberInfo.DeclaringType.Name;
            var tableName        = GetLookupTableName(memberInfo);

            return(await repository.UpdateOrCreateAsync <StorageLookupTable, TResult>(
                       hashRowKey, hashPartitionKey,
                       async (created, lookup, saveAsync) =>
            {
                if (!created)
                {
                    return onFailure();
                }

                async Task <Func <Task> > RollbackMaybeAsync()
                {
                    if (IsIgnored(memberInfo, valueExisting))
                    {
                        return default(Func <Task>);
                    }
                    return await ExecuteDeleteAsync(memberInfo, rowKeyRef, partitionKeyRef,
                                                    valueExisting, dictionaryExisting,
                                                    repository,
                                                    (rb) => rb,
                                                    () => default);
                }

                var rollbackMaybeTask = RollbackMaybeAsync();
                lookup.hashvalues = hashKeys;     // TODO: Why is this necessary?
                await saveAsync(lookup);
                var rollbackMaybe = await rollbackMaybeTask;

                Func <Task <bool> > rollback =
                    async() =>
                {
                    if (!rollbackMaybe.IsDefaultOrNull())
                    {
                        await rollbackMaybe();
                    }
                    return await repository.DeleteAsync <StorageLookupTable, bool>(hashRowKey, hashPartitionKey,
                                                                                   () => true,
                                                                                   () => false,
                                                                                   tableName: tableName);
                };
                return onSuccessWithRollback(rollback);
            },
                       tableName : tableName));
        }
        public async Task <Func <Task> > MutateLookupTable(string rowKey, string partitionKey,
                                                           MemberInfo memberInfo, AzureTableDriverDynamic repository,
                                                           Func <IEnumerable <KeyValuePair <string, string> >, IEnumerable <KeyValuePair <string, string> > > mutateCollection)
        {
            var tableName = GetLookupTableName(memberInfo);

            return(await repository.UpdateOrCreateAsync <StorageLookupTable, Func <Task> >(rowKey, partitionKey,
                                                                                           async (created, lookup, saveAsync) =>
            {
                var rollbackRowAndPartitionKeys = lookup.rowAndPartitionKeys;     // store for rollback
                lookup.rowAndPartitionKeys = mutateCollection(rollbackRowAndPartitionKeys)
                                             .Distinct(rpKey => rpKey.Key)
                                             .ToArray();
                await saveAsync(lookup);
                Func <Task <bool> > rollback =
                    async() =>
                {
                    if (created)
                    {
                        return await repository.DeleteAsync <StorageLookupTable, bool>(rowKey, partitionKey,
                                                                                       () => true,
                                                                                       () => false,
                                                                                       tableName: tableName);
                    }
                    var table = repository.TableClient.GetTableReference(tableName);
                    return await repository.UpdateAsync <StorageLookupTable, bool>(rowKey, partitionKey,
                                                                                   async(modifiedDoc, saveRollbackAsync) =>
                    {
                        bool Modified()
                        {
                            if (rollbackRowAndPartitionKeys.Length != modifiedDoc.rowAndPartitionKeys.Length)
                            {
                                return true;
                            }

                            var matchKeys = rollbackRowAndPartitionKeys.SelectKeys().AsHashSet();
                            var matchValues = rollbackRowAndPartitionKeys.SelectKeys().AsHashSet();
                            var allValuesAccountedFor = modifiedDoc.rowAndPartitionKeys
                                                        .All(
                                rowAndPartitionKey =>
                            {
                                if (!matchKeys.Contains(rowAndPartitionKey.Key))
                                {
                                    return false;
                                }
                                if (!matchValues.Contains(rowAndPartitionKey.Value))
                                {
                                    return false;
                                }
                                return true;
                            });
                            return !allValuesAccountedFor;
                        }
                        if (!Modified())
                        {
                            return true;
                        }
                        modifiedDoc.rowAndPartitionKeys = rollbackRowAndPartitionKeys;
                        await saveRollbackAsync(modifiedDoc);
                        return true;
                    },
                                                                                   table: table);
                };
                return rollback;
            },
                                                                                           tableName : tableName));
        }
        public async Task <Func <Task> > MutateLookupTable(string rowKey, string partitionKey,
                                                           MemberInfo memberInfo, AzureTableDriverDynamic repository,
                                                           Func <IEnumerable <KeyValuePair <string, string> >, IEnumerable <KeyValuePair <string, string> > > mutateCollection)
        {
            var tableName = GetLookupTableName(memberInfo);

            return(await repository.UpdateOrCreateAsync <DateTimeLookupTable, Func <Task> >(rowKey, partitionKey,
                                                                                            async (created, lookup, saveAsync) =>
            {
                // store for rollback
                var rollbackRowAndPartitionKeys = lookup.rows
                                                  .NullToEmpty()
                                                  .Zip(lookup.partitions.NullToEmpty(), (k, v) => k.PairWithValue(v))
                                                  .ToArray();
                await saveAsync(lookup);
                Func <Task <bool> > rollback =
                    async() =>
                {
                    if (created)
                    {
                        return await repository.DeleteAsync <DateTimeLookupTable, bool>(rowKey, partitionKey,
                                                                                        () => true,
                                                                                        () => false,
                                                                                        tableName: tableName);
                    }
                    var table = repository.TableClient.GetTableReference(tableName);
                    return await repository.UpdateAsync <DateTimeLookupTable, bool>(rowKey, partitionKey,
                                                                                    async(modifiedDoc, saveRollbackAsync) =>
                    {
                        bool Modified()
                        {
                            if (rollbackRowAndPartitionKeys.Length != modifiedDoc.rows.Length)
                            {
                                return true;
                            }

                            var matchKeys = rollbackRowAndPartitionKeys.SelectKeys().AsHashSet();
                            var matchValues = rollbackRowAndPartitionKeys.SelectKeys().AsHashSet();
                            var allRowAccountedFor = modifiedDoc.rows
                                                     .All(
                                row =>
                            {
                                if (!matchKeys.Contains(row))
                                {
                                    return false;
                                }
                                return true;
                            });
                            var allPartitionsAccountedFor = modifiedDoc.partitions
                                                            .All(
                                partition =>
                            {
                                if (!matchValues.Contains(partition))
                                {
                                    return false;
                                }
                                return true;
                            });
                            var allValuesAccountedFor = allRowAccountedFor & allPartitionsAccountedFor;
                            return !allValuesAccountedFor;
                        }
                        if (!Modified())
                        {
                            return true;
                        }
                        modifiedDoc.rows = rollbackRowAndPartitionKeys.SelectKeys().ToArray();
                        modifiedDoc.partitions = rollbackRowAndPartitionKeys.SelectValues().ToArray();
                        await saveRollbackAsync(modifiedDoc);
                        return true;
                    },
                                                                                    table: table);
                };
                return rollback;
            },
                                                                                            tableName : tableName));
        }