public 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) { var existingRowKey = GetRowKey(memberInfo, value); var existingPartitionKey = GetPartitionKey(memberInfo, value); var tableName = GetLookupTableName(memberInfo); return(repository.FindByIdAsync <DateTimeLookupTable, TResult>(existingRowKey, existingPartitionKey, (lookup) => { var rowAndParitionKeys = lookup.rows .NullToEmpty() .Zip(lookup.partitions.NullToEmpty(), (k, v) => k.PairWithValue(v)) .ToArray(); var rowKeyFound = rowAndParitionKeys .NullToEmpty() .Where(kvp => kvp.Key == rowKeyRef) .Any(); var partitionKeyFound = rowAndParitionKeys .NullToEmpty() .Where(kvp => kvp.Value == partitionKeyRef) .Any(); if (rowKeyFound && partitionKeyFound) { return onSuccessWithRollback(() => true.AsTask()); } return onFailure(); }, onNotFound: () => onFailure(), tableName: tableName)); }
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 static Uri GenerateBlobFileSasLink(this string containerName, string blobName, TimeSpan?lifespan = default(TimeSpan?)) { var expiresOn = lifespan.HasValue ? DateTime.UtcNow + lifespan.Value : DateTime.UtcNow.AddMinutes(15);//default SAS token expire after 15 minutes. var blobSasBuilder = new BlobSasBuilder() { BlobContainerName = containerName, BlobName = blobName, ExpiresOn = expiresOn, }; blobSasBuilder.SetPermissions(BlobSasPermissions.Write); var azureDriver = AzureTableDriverDynamic.FromSettings(); var blobClient = azureDriver.BlobClient; var sharedKeyCredential = azureDriver.StorageSharedKeyCredential; var sasToken = blobSasBuilder.ToSasQueryParameters(sharedKeyCredential).ToString(); var sasUrl = blobClient.Uri .AppendToPath(containerName) .AppendToPath(blobName) .SetQuery(sasToken); return(sasUrl); }
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) { var type = memberInfo.GetMemberType().GenericTypeArguments.First(); var rollback = await type .GetMembers(BindingFlags.Public | BindingFlags.Instance) .Where(member => member.ContainsAttributeInterface <IDeleteCascaded>()) .First <MemberInfo, Task <Func <Task> > >( (member, next) => { var cascadeAttr = member.GetAttributeInterface <IDeleteCascaded>(); if (cascadeAttr.Cascade != this.Name) { return(next()); } return(cascadeAttr.CascadeDeleteAsync(member, rowKeyRef, partitionKeyRef, value, dictionary, repository)); }, () => throw new Exception($"Cascade references property named {this.Name} on {type.FullName} which does not exists or does not contain attribute of type {typeof(IDeleteCascaded).FullName}.")); return(onSuccessWithRollback(rollback)); }
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 Task <TResult> ExecuteDeleteModifiersAsync <TResult>(AzureTableDriverDynamic repository, Func <Func <Task>, TResult> onSuccessWithRollback, Func <MemberInfo[], TResult> onFailure) { return(GetExecutionResults(repository, (memberInfo, storageModifier) => { return storageModifier.ExecuteDeleteAsync(memberInfo, this.RowKey, this.PartitionKey, this.Entity, this.WriteEntity(null), 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 virtual async Task <TResult> ExecuteAsync <TEntity, TResult>(MemberInfo memberInfo, string rowKeyRef, string partitionKeyRef, TEntity value, IDictionary <string, EntityProperty> dictionary, AzureTableDriverDynamic repository, Func <Func <Task>, TResult> onSuccessWithRollback, Func <TResult> onFailure) { var propertyValueType = memberInfo.GetMemberType(); var rowKeyValue = memberInfo.GetValue(value); var referencedEntityType = ReferenceType.IsDefaultOrNull() ? propertyValueType.GetGenericArguments().First() : ReferenceType; if (!propertyValueType.IsSubClassOfGeneric(typeof(IRef <>))) { throw new Exception($"`{propertyValueType.FullName}` is instance of IRef<>"); } Task <TResult> result = (Task <TResult>) this.GetType() .GetMethod("ExecuteTypedAsync", BindingFlags.Public | BindingFlags.Instance) .MakeGenericMethod(typeof(TEntity), referencedEntityType, typeof(TResult)) .Invoke(this, new object[] { rowKeyValue, memberInfo, rowKeyRef, partitionKeyRef, value, dictionary, repository, onSuccessWithRollback, onFailure }); return(await result); }
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 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 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)); }
// NOTE: This table will contain duplication indexes. // This is important so rollback can undo exactly what it did. // Removal of duplicate entries inside of Execution Chain can // result in data loss during concurrent operations. public virtual async Task <TResult> ExecuteAsync <TEntity, TResult>(MemberInfo memberInfo, string rowKeyRef, string partitionKeyRef, TEntity value, IDictionary <string, EntityProperty> dictionary, AzureTableDriverDynamic repository, Func <IEnumerable <KeyValuePair <string, string> >, IEnumerable <KeyValuePair <string, string> > > mutateCollection, Func <Func <Task>, TResult> onSuccessWithRollback, Func <TResult> onFailure) { var rollbacks = await GetKeys(memberInfo, value) .Select( lookupKey => { return(MutateLookupTable(lookupKey.RowKey, lookupKey.PartitionKey, memberInfo, repository, mutateCollection)); }) .WhenAllAsync(); Func <Task> allRollbacks = () => { var tasks = rollbacks.Select(rb => rb()); return(Task.WhenAll(tasks)); }; return(onSuccessWithRollback(allRollbacks)); }
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)); }
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)); }
public 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) { return(onFailure().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, 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) { 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 StorageQueryProvideQuery(AzureTableDriverDynamic storageDriver) : base( (queryProvider, type) => (queryProvider is StorageQuery <TResource>)? (queryProvider as StorageQuery <TResource>).From() : new StorageQuery <TResource>(storageDriver), (queryProvider, expression, type) => (queryProvider is StorageQuery <TResource>) ? (queryProvider as StorageQuery <TResource>).FromExpression(expression) : new StorageQuery <TResource>(storageDriver, expression)) { }
internal static AzureTableDriverDynamic GetRepository(string connectionString) { if (!repositories.TryGetValue(connectionString, out AzureTableDriverDynamic repository)) { repository = AzureTableDriverDynamic.FromStorageString(connectionString); if (!repositories.TryAdd(connectionString, repository)) { repositories.TryGetValue(connectionString, out repository); } } return(repository); }
public virtual Task <IHttpResponse> InstigatorDelegateGeneric(Type type, IApplication httpApp, IHttpRequest routeData, ParameterInfo parameterInfo, Func <object, Task <IHttpResponse> > onSuccess) { var constructor = typeof(StorageQuery <>) .MakeGenericType(type.GenericTypeArguments) .GetConstructors(BindingFlags.Public | BindingFlags.Instance) .First(); var parameter = AzureTableDriverDynamic.FromSettings(); var sq = constructor.Invoke(parameter.AsArray()); return(onSuccess(sq)); }
public async Task <TResult> ExecuteCreateModifiersAsync <TResult>(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.ExecuteCreateAsync(memberInfo, this.RowKey, this.PartitionKey, this.Entity, this.WriteEntity(null), repository, rollback => new ExecResult { success = true, rollback = rollback, member = memberInfo, }, () => new ExecResult { success = false, member = memberInfo, })); })) .AsyncEnumerable() .ToArrayAsync(); var rollbacks = modifierResults .Where(result => result.success) .Select(result => result.rollback()); var failures = modifierResults .Where(result => !result.success) .Select(result => result.member); var didFail = failures.Any(); if (didFail) { await Task.WhenAll(rollbacks); return(onFailure(failures.ToArray())); } return(onSuccessWithRollback( () => Task.WhenAll(rollbacks))); }
public static async Task <HttpResponseMessage> QueueUpBackupPartitions( [Property(Name = IdPropertyName)] IRef <RepositoryBackup> repositoryBackupRef, [Property(Name = StorageSettingCopyFromPropertyName)] string storageSettingCopyFrom, [Property(Name = StorageSettingCopyToPropertyName)] string storageSettingCopyTo, [Resource] RepositoryBackup repositoryBackup, AzureApplication application, RequestMessage <TableBackup> requestQuery, HttpRequestMessage request, EastFive.Analytics.ILogger logger, MultipartResponseAsync <InvocationMessage> onQueued, AlreadyExistsResponse onAlreadyExists) { logger.Trace($"Cleaning backup results"); var repo = AzureTableDriverDynamic.FromStorageString(storageSettingCopyTo); await DeleteAllAsync(GetRepository(storageSettingCopyTo)); CloudStorageAccount account = CloudStorageAccount .Parse(storageSettingCopyFrom); CloudTableClient tableClient = new CloudTableClient(account.TableEndpoint, account.Credentials); return(await await repositoryBackup.StorageCreateAsync( (discard) => { var resourceInfoToProcess = tableClient .ListTables() .Distinct() .Select( async cloudTable => { var tableBackup = new TableBackup() { tableBackupRef = Ref <TableBackup> .NewRef(), backup = repositoryBackupRef, tableName = cloudTable.Name, when = DateTime.UtcNow, }; var invocationMessage = await requestQuery .HttpPost(tableBackup) .CompileRequest(request) .FunctionAsync(); logger.Trace($"Invocation[{invocationMessage.id}] will backup table `{tableBackup.tableName}`."); return invocationMessage; }) .AsyncEnumerable(); return onQueued(resourceInfoToProcess); }, () => onAlreadyExists().AsTask())); }
public 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) { return(ExecuteAsync(memberInfo, rowKeyRef, partitionKeyRef, value, dictionary, repository, onSuccessWithRollback, onFailure)); }
public virtual Task <TResult> ExecuteCreateAsync <TEntity, TResult>(MemberInfo memberInfo, string rowKeyRef, string partitionKeyRef, TEntity value, IDictionary <string, EntityProperty> dictionary, AzureTableDriverDynamic repository, Func <Func <Task>, TResult> onSuccessWithRollback, Func <TResult> onFailure) { return(ExecuteAsync(memberInfo, rowKeyRef, partitionKeyRef, value, dictionary, repository, (rowAndParitionKeys) => rowAndParitionKeys.NullToEmpty().Append(rowKeyRef.PairWithValue(partitionKeyRef)), onSuccessWithRollback, onFailure)); }
public Task <TResult> ExecuteDeleteModifiersAsync <TResult>(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 static Task CreateOrUpdateAsync(AzureTableDriverDynamic destRepo, string resource, string filter, int?count = default, double?seconds = default) { var backupRef = GetBackupRef(resource, filter); return(destRepo.UpdateOrCreateAsync <Backup, Backup>( backupRef.StorageComputeRowKey(), backupRef.StorageComputePartitionKey(), async(created, storageToUpdate, saveAsync) => { storageToUpdate.resource = resource; storageToUpdate.filter = filter; storageToUpdate.count = count; storageToUpdate.seconds = seconds; await saveAsync(storageToUpdate); return storageToUpdate; })); }
public 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) { return(ExecuteAsync(memberInfo, rowKeyRef, partitionKeyRef, value, dictionary, repository, (rowAndParitionKeys) => rowAndParitionKeys .NullToEmpty() .Where(kvp => kvp.Key != rowKeyRef && kvp.Value != partitionKeyRef), onSuccessWithRollback, onFailure)); }
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 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()))); }
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) { var existingRowKeys = GetKeys(memberInfo, value); var tableName = GetLookupTableName(memberInfo); var missingRows = existingRowKeys .Select( async astKey => { var isGood = await repository.FindByIdAsync <StorageLookupTable, bool>(astKey.RowKey, astKey.PartitionKey, (lookup, tableResult) => { var rowAndParitionKeys = lookup.rowAndPartitionKeys; var rowKeyFound = rowAndParitionKeys .NullToEmpty() .Where(kvp => kvp.Key == rowKeyRef) .Any(); var partitionKeyFound = rowAndParitionKeys .NullToEmpty() .Where(kvp => kvp.Value == partitionKeyRef) .Any(); if (rowKeyFound && partitionKeyFound) { return(true); } return(false); }, onNotFound: () => false, tableName: tableName); return(isGood); }) .AsyncEnumerable() .Where(item => !item); if (await missingRows.AnyAsync()) { return(onFailure()); } return(onSuccessWithRollback(() => 1.AsTask())); }