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)); }
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()); }
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()); }
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)); }