public Task <TResult> ExecuteUpdateModifiersAsync <TResult>(IAzureStorageTableEntity <EntityType> current,
                                                             AzureTableDriverDynamic repository,
                                                             Func <Func <Task>, TResult> onSuccessWithRollback,
                                                             Func <MemberInfo[], TResult> onFailure)
 {
     return(GetExecutionResults(repository,
                                (memberInfo, storageModifier) =>
     {
         return storageModifier.ExecuteUpdateAsync(memberInfo,
                                                   this, current,
                                                   repository,
                                                   rollback =>
         {
             return new ExecResult
             {
                 success = true,
                 rollback = rollback,
                 member = memberInfo,
             };
         },
                                                   () =>
         {
             return new ExecResult
             {
                 success = false,
                 rollback = default(Func <Task>),
                 member = memberInfo,
             };
         });
     },
                                onSuccessWithRollback: onSuccessWithRollback,
                                onFailure: onFailure));
 }
Beispiel #2
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> ExecuteUpdateAsync <TEntity, TResult>(MemberInfo memberInfo,
                                                                          IAzureStorageTableEntity <TEntity> updatedEntity, IAzureStorageTableEntity <TEntity> existingEntity,
                                                                          AzureTableDriverDynamic repository,
                                                                          Func <Func <Task>, TResult> onSuccessWithRollback,
                                                                          Func <TResult> onFailure)
        {
            var newValue      = memberInfo.GetValue(updatedEntity.Entity);
            var existingValue = memberInfo.GetValue(updatedEntity.Entity);

            if (newValue.GetType().IsAssignableTo(typeof(System.Delegate)))
            {
                var dele     = (Delegate)newValue;
                var deleType = dele.Target.GetType();
                if (deleType.DeclaringType.GUID == typeof(StorageSubtableAttribute).GUID)
                {
                    return(onSuccessWithRollback(() => true.AsTask()));
                }
            }

            var rowKeyRef       = updatedEntity.RowKey;
            var partitionKeyRef = updatedEntity.PartitionKey;

            var memberType  = typeof(TEntity);
            var taskValue   = newValue.ExecuteFunction(out Type taskType);
            var resultValue = await taskValue.CastAsTaskObjectAsync(out Type typeToSave);

            var rawValues = Serialize(resultValue, typeToSave);

            ITableEntity subtableEntity = new SubtableEntity(rowKeyRef, partitionKeyRef, rawValues);
            var          tableName      = StorageLookupAttribute.GetMemberTableName(memberInfo);
            var          tableRef       = repository.TableClient.GetTableReference(tableName);

            return(await repository.InsertOrReplaceAsync(subtableEntity, new E5CloudTable(tableRef),
                                                         (created, tr) => onSuccessWithRollback(() => 1.AsTask())));
        }
 public Task <TResult> ExecuteUpdateAsync <TEntity, TResult>(MemberInfo memberInfo,
                                                             IAzureStorageTableEntity <TEntity> updatedEntity,
                                                             IAzureStorageTableEntity <TEntity> existingEntity,
                                                             AzureTableDriverDynamic repository,
                                                             Func <Func <Task>, TResult> onSuccessWithRollback,
                                                             Func <TResult> onFailure)
 {
     return(onSuccessWithRollback(() => true.AsTask()).AsTask());
 }
 public Task <TResult> ExecuteUpdateAsync <TEntity, TResult>(MemberInfo memberInfo,
                                                             IAzureStorageTableEntity <TEntity> updatedEntity,
                                                             IAzureStorageTableEntity <TEntity> existingEntity,
                                                             AzureTableDriverDynamic repository,
                                                             Func <Func <Task>, TResult> onSuccessWithRollback,
                                                             Func <TResult> onFailure)
 {
     // Since only updating the row/partition keys could force a change here, just ignroe
     return(onSuccessWithRollback(
                () => true.AsTask()).AsTask());
 }
Beispiel #6
0
        public Task <TResult> ExecuteUpdateModifiersAsync <TResult>(IAzureStorageTableEntity <EntityType> current, AzureTableDriverDynamic repository,
                                                                    Func <Func <Task>, TResult> onSuccessWithRollback,
                                                                    Func <MemberInfo[], TResult> onFailure)
        {
            var hasModifiers = typeof(EntityType)
                               .GetPropertyOrFieldMembers()
                               .Where(member => member.ContainsAttributeInterface <IModifyAzureStorageTableSave>())
                               .Any();

            if (hasModifiers)
            {
                throw new NotImplementedException("Please use the non-depricated StorageTableAttribute with modifier classes");
            }

            return(onSuccessWithRollback(
                       () => 1.AsTask()).AsTask());
        }
Beispiel #7
0
        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 existingRowKeys   = GetKeys(memberInfo, existingEntity.Entity);
            var updatedRowKeys    = GetKeys(memberInfo, updatedEntity.Entity);
            var rowKeysDeleted    = existingRowKeys.Except(updatedRowKeys, rk => $"{rk.RowKey}|{rk.PartitionKey}");
            var rowKeysAdded      = updatedRowKeys.Except(existingRowKeys, rk => $"{rk.RowKey}|{rk.PartitionKey}");
            var deletionRollbacks = rowKeysDeleted
                                    .Select(
                rowKey =>
            {
                return(MutateLookupTable(rowKey.RowKey, rowKey.PartitionKey, memberInfo,
                                         repository,
                                         (rowAndParitionKeys) => rowAndParitionKeys
                                         .NullToEmpty()
                                         .Where(kvp =>
                                                kvp.Key != existingEntity.RowKey &&
                                                kvp.Value != existingEntity.PartitionKey)
                                         .ToArray()));
            });
            var additionRollbacks = rowKeysAdded
                                    .Select(
                rowKey =>
            {
                return(MutateLookupTable(rowKey.RowKey, rowKey.PartitionKey, memberInfo,
                                         repository,
                                         (rowAndParitionKeys) => rowAndParitionKeys
                                         .NullToEmpty()
                                         .Append(updatedEntity.RowKey.PairWithValue(updatedEntity.PartitionKey))
                                         .ToArray()));
            });
            var allRollbacks = await additionRollbacks.Concat(deletionRollbacks).WhenAllAsync();

            Func <Task> allRollback =
                () =>
            {
                var tasks = allRollbacks.Select(rb => rb());
                return(Task.WhenAll(tasks));
            };

            return(onSuccessWithRollback(allRollback));
        }
            public async Task <TResult> ExecuteUpdateModifiersAsync <TResult>(IAzureStorageTableEntity <EntityType> current,
                                                                              AzureTableDriverDynamic repository,
                                                                              Func <Func <Task>, TResult> onSuccessWithRollback,
                                                                              Func <MemberInfo[], TResult> onFailure)
            {
                var modifierResults = await typeof(EntityType)
                                      .GetPropertyOrFieldMembers()
                                      .Where(member => member.ContainsAttributeInterface <IModifyAzureStorageTableSave>())
                                      .SelectMany(memberInfo =>
                                                  memberInfo
                                                  .GetAttributesInterface <IModifyAzureStorageTableSave>()
                                                  .Select(
                                                      storageModifier =>
                {
                    return(storageModifier.ExecuteUpdateAsync(memberInfo,
                                                              this.RowKey, this.PartitionKey,
                                                              current.Entity, current.WriteEntity(null),
                                                              this.Entity, this.WriteEntity(null),
                                                              repository,
                                                              rollback => rollback.PairWithKey(true),
                                                              () => default(Func <Task>).PairWithKey(false)));
                }))
                                      .AsyncEnumerable()
                                      .ToArrayAsync();
                var rollbacks = modifierResults
                                .Where(kvp => kvp.Key)
                                .SelectValues(callback => callback());
                var didFail = modifierResults
                              .Where(kvp => !kvp.Key)
                              .Any();

                if (didFail)
                {
                    await Task.WhenAll(rollbacks);

                    return(onFailure(new MemberInfo[] { }));
                }

                return(onSuccessWithRollback(
                           () => Task.WhenAll(rollbacks)));
            }
        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));
        }