internal async Task <TResult> MarkInviteRedeemedAsync <TResult>(Guid inviteToken, Guid loginId, Func <Guid, TResult> onFound, Func <TResult> onNotFound, Func <Guid, TResult> onAlreadyRedeemed, Func <TResult> onAlreadyInUse, Func <TResult> onAlreadyConnected) { var lookupResults = await await repository.FindByIdAsync(inviteToken, async (Documents.InviteTokenDocument tokenDocument) => { var rollback = new RollbackAsync <TResult>(); rollback.AddTaskUpdate(tokenDocument.InviteId, (Documents.InviteDocument inviteDoc) => { inviteDoc.LoginId = loginId; }, (inviteDoc) => { inviteDoc.LoginId = default(Guid?); }, onNotFound, this.repository); var loginLookup = new Documents.LoginActorLookupDocument() { ActorId = tokenDocument.ActorId, }; rollback.AddTaskCreate(loginId, loginLookup, onAlreadyInUse, this.repository); return(await rollback.ExecuteAsync(() => onFound(tokenDocument.ActorId))); }, () => onNotFound().ToTask()); return(lookupResults); }
public async Task <TResult> CreatePasswordCredentialAsync <TResult>(Guid passwordCredentialId, Guid actorId, Guid loginId, DateTime?emailLastSent, Func <TResult> onSuccess, Func <TResult> onAlreadyExists, Func <TResult> onRelationshipAlreadyExists, Func <TResult> onLoginAlreadyUsed) { var rollback = new RollbackAsync <TResult>(); var lookupDoc = new Documents.LoginActorLookupDocument { ActorId = actorId, }; rollback.AddTaskCreate(loginId, lookupDoc, onLoginAlreadyUsed, this.repository); rollback.AddTaskCreateOrUpdate(actorId, (Documents.ActorMappingsDocument actorDoc) => actorDoc.AddPasswordCredential(passwordCredentialId), actorDoc => actorDoc.RemovePasswordCredential(passwordCredentialId), onRelationshipAlreadyExists, this.repository); var passwordCredentialDoc = new Documents.PasswordCredentialDocument { LoginId = loginId, EmailLastSent = emailLastSent, }; rollback.AddTaskCreate(passwordCredentialId, passwordCredentialDoc, onAlreadyExists, this.repository); return(await rollback.ExecuteAsync(onSuccess)); }
public static void AddTaskDeleteJoin <TRollback, TDocument>(this RollbackAsync <Guid?, TRollback> rollback, Guid docId, Func <TDocument, Guid?> removeLink, Action <Guid, TDocument> rollbackLink, AzureStorageRepository repo) where TDocument : class, ITableEntity { rollback.AddTaskUpdate(docId, (TDocument doc) => { var joinId = removeLink(doc); return(joinId); }, (joinId, doc) => { if (joinId.HasValue) { rollbackLink(joinId.Value, doc); return(true); } return(false); }, () => default(Guid?), repo); }
public async Task <TResult> CreateUnauthenticatedAsync <TResult>(Guid integrationId, Guid accountId, string methodName, Func <TResult> onSuccess, Func <TResult> onAlreadyExists) { var rollback = new RollbackAsync <TResult>(); var docByMethod = new AccessDocument { LookupId = integrationId, Method = methodName, }; rollback.AddTaskCreate(accountId, methodName, docByMethod, onAlreadyExists, this.repository); var docById = new AccessDocument { LookupId = accountId, Method = methodName, }; rollback.AddTaskCreate(integrationId, docById, onAlreadyExists, this.repository); return(await rollback.ExecuteAsync(onSuccess)); }
internal async Task <TResult> CreateCredentialMappingAsync <TResult>(Guid credentialMappingId, CredentialValidationMethodTypes method, string subjectId, Guid actorId, Func <TResult> onSuccess, Func <TResult> onAlreadyExists, Func <TResult> onTokenAlreadyInUse) { var rollback = new RollbackAsync <TResult>(); var methodName = Enum.GetName(typeof(CredentialValidationMethodTypes), method); var credentialMappingDoc = new Documents.CredentialMappingDocument() { Method = methodName, Subject = subjectId, ActorId = actorId, }; rollback.AddTaskCreate(credentialMappingId, credentialMappingDoc, onAlreadyExists, this.repository); var lookupDocument = new Azure.Documents.CredentialMappingLookupDocument() { CredentialMappingId = credentialMappingId, Method = methodName, Subject = subjectId, }; rollback.AddTaskCreate(subjectId, methodName, lookupDocument, onTokenAlreadyInUse, this.repository); rollback.AddTaskCreateOrUpdate(actorId, (Documents.ActorMappingsDocument authDoc) => authDoc.AddInviteId(credentialMappingId), (authDoc) => authDoc.RemoveInviteId(credentialMappingId), onAlreadyExists, // This should fail on the action above as well this.repository); return(await rollback.ExecuteAsync(onSuccess)); }
public async Task <TResult> CreateAuthenticatedAsync <TResult>(Guid integrationId, Guid authenticationId, string methodName, IDictionary <string, string> paramSet, Func <TResult> onSuccess, Func <TResult> onAlreadyExists) { var rollback = new RollbackAsync <TResult>(); var docByMethod = new AccessDocument { LookupId = integrationId, Method = methodName, }; rollback.AddTaskCreate(authenticationId, methodName, docByMethod, onAlreadyExists, this.repository); var integrationDoc = new AuthenticationRequestDocument { LinkedAuthenticationId = authenticationId, Method = methodName, Action = Enum.GetName(typeof(AuthenticationActions), AuthenticationActions.access) }; integrationDoc.SetExtraParams(paramSet); rollback.AddTaskCreate(integrationId, integrationDoc, onAlreadyExists, this.repository); return(await rollback.ExecuteAsync(onSuccess)); }
public async Task <TResult> CreateAsync <TResult>(Guid integrationId, Guid accountId, CredentialValidationMethodTypes method, IDictionary <string, string> paramSet, Func <TResult> onSuccess, Func <TResult> onAlreadyExists) { var methodName = Enum.GetName(typeof(CredentialValidationMethodTypes), method); var docByMethod = new AccessDocument { LookupId = integrationId, Method = methodName, }; docByMethod.SetExtraParams(paramSet); var docById = new AccessDocument { LookupId = accountId, Method = methodName, }; docById.SetExtraParams(paramSet); var rollback = new RollbackAsync <TResult>(); rollback.AddTaskCreate(accountId, methodName, docByMethod, onAlreadyExists, this.repository); rollback.AddTaskCreate(integrationId, docById, onAlreadyExists, this.repository); return(await rollback.ExecuteAsync(onSuccess)); }
internal static Task <TResult> CreateAsync <TResult>(Guid processStageId, Guid actorId, Guid processStageTypeId, string title, KeyValuePair <Guid[], Guid>[] confirmableActorIds, Guid[] editableActorIds, Guid[] viewableActorIds, Func <TResult> onSuccess, Func <TResult> onAlreadyExists) { return(AzureStorageRepository.Connection( azureStorageRepository => { var rollback = new RollbackAsync <TResult>(); var procStageDoc = new ProcessStageDocument() { Owner = actorId, ProcessStageType = processStageTypeId, Title = title, }; procStageDoc.SetConfirmables(confirmableActorIds); procStageDoc.SetEditables(editableActorIds); procStageDoc.SetViewables(viewableActorIds); rollback.AddTaskCreate(processStageId, procStageDoc, onAlreadyExists, azureStorageRepository); rollback.AddTaskCreateOrUpdate <TResult, Documents.ProcessStageActorLookupDocument>(actorId, (created, lookupDoc) => lookupDoc.AddLookupDocumentId(processStageId), lookupDoc => lookupDoc.RemoveLookupDocumentId(processStageId), azureStorageRepository); return rollback.ExecuteAsync(onSuccess); })); }
public async Task <TResult> CreateAsync <TResult>( Guid id, Guid actorId, string name, Func <TResult> onSuccess, Func <TResult> onAlreadyExists, Func <TResult> onActorNotFound) { var rollback = new RollbackAsync <TResult>(); var document = new Documents.RoleDocument() { Name = name, ActorId = actorId, }; rollback.AddTaskCreate(id, document, onAlreadyExists, this.azureStorageRepository); rollback.AddTaskCreateOrUpdate(actorId, (Documents.ActorMappingsDocument actorDoc) => { actorDoc.AddRole(id); return(true); }, (actorDoc) => actorDoc.RemoveRole(id), onActorNotFound, this.azureStorageRepository); return(await rollback.ExecuteAsync(onSuccess)); }
public static Task <TResult> Transaction <TResult>(Func <RollbackAsync <TResult>, AzureStorageRepository, Func <TResult> > onConnected) { return(AzureStorageRepository.Connection( connection => { var rollback = new RollbackAsync <TResult>(); var onSuccess = onConnected(rollback, connection); return rollback.ExecuteAsync(onSuccess); })); }
public static void AddTaskCreateOrUpdate <TRollback, TDocument>(this RollbackAsync <TRollback> rollback, Guid docId, string partitionKey, Func <bool, TDocument, bool> isMutated, Action <TDocument> mutateRollback, AzureStorageRepository repo) where TDocument : class, ITableEntity { rollback.AddTask( (success, failure) => { return(repo.CreateOrUpdateAsync <TDocument, RollbackAsync <TRollback> .RollbackResult>(docId, partitionKey, async(created, doc, save) => { if (!isMutated(created, doc)) { return success( async() => { if (created) { await repo.DeleteAsync(doc, () => true, () => false); } }); } await save(doc); return success( async() => { if (created) { await repo.DeleteIfAsync <TDocument, bool>(docId, async(docDelete, delete) => { // TODO: Check etag if(docDelete.ET) await delete(); return true; }, () => false); return; } await repo.UpdateAsync <TDocument, bool>(docId, async(docRollback, saveRollback) => { mutateRollback(docRollback); await saveRollback(docRollback); return true; }, () => false); }); })); }); }
public static void AddTaskCheckup <TRollback, TDocument>(this RollbackAsync <TRollback> rollback, Guid docId, Func <TRollback> onDoesNotExists, AzureStorageRepository repo) where TDocument : class, ITableEntity { rollback.AddTask( async(success, failure) => { return(await repo.FindByIdAsync(docId, (TDocument doc) => success(() => 1.ToTask()), () => failure(onDoesNotExists()))); }); }
public static void AddTaskAsyncCreateOrUpdate <TRollback, TDocument>(this RollbackAsync <TRollback> rollback, Guid docId, Func <TDocument, Task <bool> > isValidAndMutate, Func <TDocument, Task <bool> > mutateRollback, Func <TRollback> onFail, AzureStorageRepository repo) where TDocument : class, ITableEntity { rollback.AddTask( (success, failure) => { return(repo.CreateOrUpdateAsync <TDocument, RollbackAsync <TRollback> .RollbackResult>(docId, async(created, doc, save) => { if (!await isValidAndMutate(doc)) { return failure(onFail()); } await save(doc); return success( async() => { if (created) { await repo.DeleteIfAsync <TDocument, bool>(docId, async(docDelete, delete) => { // TODO: Check etag if(docDelete.ET) await delete(); return true; }, () => false); return; } await repo.UpdateAsync <TDocument, bool>(docId, async(docRollback, saveRollback) => { if (await mutateRollback(docRollback)) { await saveRollback(docRollback); } return true; }, () => false); }); })); }); }
public static void AddTaskAsyncUpdate <TRollback, TDocument>(this RollbackAsync <TRollback> rollback, Guid docId, Func <TDocument, Task <bool> > mutateUpdate, Func <TDocument, Task> mutateRollback, Func <TRollback> onNotFound, AzureStorageRepository repo) where TDocument : class, ITableEntity { rollback.AddTask( async(success, failure) => { var r = await repo.UpdateAsync <TDocument, int>(docId, async(doc, save) => { if (!await mutateUpdate(doc)) { return(1); } await save(doc); return(0); }, () => - 1); if (r == 0) { return(success( async() => { await repo.UpdateAsync <TDocument, bool>(docId, async(doc, save) => { await mutateRollback(doc); await save(doc); return true; }, () => false); })); } if (r == 1) { return(success(() => true.ToTask())); } return(failure(onNotFound())); }); }
public async Task <TResult> CreateOrUpdateAsync <TResult>(Guid actorId, Guid claimId, string type, string value, Func <TResult> onSuccess, Func <TResult> onFailure, Func <TResult> onActorNotFound) { return(await await repository.FindLinkedDocumentsAsync <ActorMappingsDocument, ClaimDocument, Task <TResult> >(actorId, (ActorMappingsDocument actorMappingsDocument) => actorMappingsDocument.Claims.ToGuidsFromByteArray(), async (ActorMappingsDocument actorMappingsDocument, ClaimDocument[] claimDocuments) => { var claimDocs = claimDocuments.Where( doc => string.Compare(doc.Type, type, StringComparison.OrdinalIgnoreCase) == 0) .ToArray(); if (claimDocs.Length >= 1) { var claimDoc = claimDocs[0]; return await repository.UpdateAsync <ClaimDocument, TResult>(claimDoc.ClaimId, async(currentDoc, saveAsync) => { currentDoc.Value = value; await saveAsync(currentDoc); return onSuccess(); }, () => onFailure()); } var rollback = new RollbackAsync <TResult>(); var newClaimDoc = new ClaimDocument() { ClaimId = claimId, Issuer = actorId.ToString("N"), //TODO - Is this is the correct issuer data??? Type = type, Value = value }; rollback.AddTaskCreate(claimId, newClaimDoc, onFailure, repository); rollback.AddTaskUpdate(actorId, (ActorMappingsDocument actorMapDocument) => actorMapDocument.AddClaim(claimId), (actorMapDocument) => actorMapDocument.RemoveClaim(claimId), onActorNotFound, repository); return await rollback.ExecuteAsync(onSuccess); }, () => onActorNotFound().ToTask())); }
public static void AddTaskUpdate <T, TRollback, TDocument>(this RollbackAsync <TRollback> rollback, Guid docId, Func < TDocument, Func <T, UpdateCallback <T> >, // Save + Success Func <UpdateCallback <T> >, // No Save + Success UpdateCallback <T> > mutateUpdate, Func <T, TDocument, bool> mutateRollback, Func <TRollback> onNotFound, AzureStorageRepository repo) where TDocument : class, ITableEntity { rollback.AddTaskUpdate(docId, (doc, save, successNoSave, fail) => mutateUpdate(doc, save, successNoSave), mutateRollback, "This version of update does not support a failure case".AsFunctionException <TRollback>(), // should never happen onNotFound, repo); }
public static void AddTaskCreate <TRollback, TDocument>(this RollbackAsync <TRollback> rollback, Guid docId, string partitionKey, TDocument document, Func <TRollback> onAlreadyExists, AzureStorageRepository repo) where TDocument : class, ITableEntity { rollback.AddTask( async(success, failure) => { return(await repo.CreateAsync(docId, partitionKey, document, () => success( async() => { await repo.DeleteIfAsync <TDocument, bool>(docId, partitionKey, async(doc, delete) => { await delete(); return true; }, () => false); }), () => failure(onAlreadyExists()))); }); }
public static void AddTaskUpdate <T, TRollback, TDocument>(this RollbackAsync <T, TRollback> rollback, Guid docId, Func <TDocument, T> mutateUpdate, Func <T, TDocument, bool> mutateRollback, Func <T> ifNotFound, AzureStorageRepository repo) where TDocument : class, ITableEntity { rollback.AddTask( async(success, failure) => { var r = await repo.UpdateAsync <TDocument, Carry <T>?>(docId, async(doc, save) => { var carry = mutateUpdate(doc); await save(doc); return(new Carry <T> { carry = carry, }); }, () => default(Carry <T>?)); if (r.HasValue) { return(success(r.Value.carry, async() => { await repo.UpdateAsync <TDocument, bool>(docId, async(doc, save) => { mutateRollback(r.Value.carry, doc); await save(doc); return true; }, () => false); })); } return(success(ifNotFound(), () => ((object)null).ToTask())); }); }
public static void AddTaskUpdate <TRollback, TDocument>(this RollbackAsync <TRollback> rollback, Guid docId, Func < TDocument, Func <UpdateCallback <bool> >, // Save + Success Func <UpdateCallback <bool> >, // No Save + Success Func <UpdateCallback <bool> >, // Reject UpdateCallback <bool> > mutateUpdate, Func <TDocument, bool> mutateRollback, Func <TRollback> onMutateRejected, Func <TRollback> onNotFound, AzureStorageRepository repo) where TDocument : class, ITableEntity { rollback.AddTaskUpdate <bool, TRollback, TDocument>(docId, (doc, save, successNoSave, reject) => mutateUpdate(doc, () => save(true), () => successNoSave(), () => reject()), (throwAway, doc) => { mutateRollback(doc); return(true); }, onMutateRejected, onNotFound, repo); }
public static void AddTaskUpdate <T, TRollback, TDocument>(this RollbackAsync <TRollback> rollback, Guid docId, Func < TDocument, Func <T, UpdateCallback <T> >, // Save + Success Func <UpdateCallback <T> >, // No Save + Success Func <UpdateCallback <T> >, // Reject UpdateCallback <T> > mutateUpdate, Func <T, TDocument, bool> mutateRollback, Func <TRollback> onMutateRejected, Func <TRollback> onNotFound, AzureStorageRepository repo) where TDocument : class, ITableEntity { rollback.AddTask( async(success, failure) => { var r = await repo.UpdateAsync <TDocument, UpdateCallback <T> >(docId, async(doc, save) => { var passThrough = mutateUpdate(doc, (passThroughSuccess) => UpdateCallback <T> .Save(passThroughSuccess), () => UpdateCallback <T> .SuccessNoSave(), () => UpdateCallback <T> .Reject()); if (passThrough.save) { await save(doc); } return(passThrough); }, () => UpdateCallback <T> .NotFound()); if (!r.found) { return(failure(onNotFound())); } if (!r.success) { return(failure(onMutateRejected())); } return(success( async() => { if (r.save) { await repo.UpdateAsync <TDocument, bool>(docId, async(doc, save) => { if (mutateRollback(r.t, doc)) { await save(doc); } return true; }, () => false); } // If this was not saved, there is no reason to do anything on the rollback })); }); }
internal async Task <TResult> CreateCredentialMappingAsync <TResult>(Guid credentialMappingId, Guid loginId, Guid actorId, string email, Guid token, DateTime lastSent, bool isToken, bool overrideLoginId, Func <TResult> onSuccess, Func <TResult> onAlreadyExists, Func <TResult> onTokenAlreadyInUse, Func <TResult> onLoginAlreadyInUse) { var rollback = new RollbackAsync <TResult>(); var inviteDocument = new Documents.InviteDocument() { ActorId = actorId, Email = email, IsToken = isToken, LastSent = lastSent, Token = token, LoginId = loginId, }; rollback.AddTaskCreate(credentialMappingId, inviteDocument, onAlreadyExists, this.repository); var inviteTokenDocument = new Documents.InviteTokenDocument() { ActorId = actorId, InviteId = credentialMappingId, }; rollback.AddTaskCreate(token, inviteTokenDocument, onTokenAlreadyInUse, this.repository); if (overrideLoginId) { var oldActorId = default(Guid); rollback.AddTaskCreateOrUpdate(loginId, (Documents.LoginActorLookupDocument loginActorDocument) => { oldActorId = loginActorDocument.ActorId; loginActorDocument.ActorId = actorId; return(true); }, (loginActorDocument) => { loginActorDocument.ActorId = oldActorId; return(true); }, () => { throw new Exception("Login override failed"); }, // Should never happend because always return true on mutate this.repository); } else { var loginActorDocument = new Documents.LoginActorLookupDocument() { ActorId = actorId, }; rollback.AddTaskCreate(loginId, loginActorDocument, onLoginAlreadyInUse, this.repository); } rollback.AddTaskCreateOrUpdate(actorId, (Documents.ActorMappingsDocument authDoc) => authDoc.AddInviteId(credentialMappingId), (authDoc) => authDoc.RemoveInviteId(credentialMappingId), onAlreadyExists, // This should fail on the action above as well this.repository); return(await rollback.ExecuteAsync(onSuccess)); }
public static async Task <TResult> AddJoinAsync <TJoin, TDocJoin, TDoc1, TDoc2, TResult>(this AzureStorageRepository repo, Guid id, Guid id1, Guid id2, TDocJoin document, Func <TDoc1, TJoin[]> getJoins1, Func <TDoc2, TJoin[]> getJoins2, Func <TJoin, Guid> id1FromJoin, Func <TJoin, Guid> id2FromJoin, Action <TDoc1> mutateUpdate1, Action <TDoc1> mutateRollback1, Action <TDoc2> mutateUpdate2, Action <TDoc2> mutateRollback2, Func <TResult> onSuccess, Func <TResult> joinIdAlreadyExist, Func <TJoin, TResult> joinAlreadyExist, Func <TResult> doc1DoesNotExist, Func <TResult> doc2DoesNotExist) where TDocJoin : class, ITableEntity where TDoc1 : class, ITableEntity where TDoc2 : class, ITableEntity { var parallel = new RollbackAsync <TResult>(); var duplicateJoin1 = default(TJoin); parallel.AddTaskUpdate <Guid, TResult, TDoc1>(id1, (doc, successSave, successNoSave, reject) => { var matches = getJoins1(doc).Where(join => id2FromJoin(join) == id2).ToArray(); if (matches.Length > 0) { duplicateJoin1 = matches[0]; return(reject()); } mutateUpdate1(doc); return(successSave(id1)); }, (id1Again, doc) => { mutateRollback1(doc); return(true); }, () => joinAlreadyExist(duplicateJoin1), doc1DoesNotExist, repo); var duplicateJoin2 = default(TJoin); parallel.AddTaskUpdate <Guid, TResult, TDoc2>(id2, (doc, successSave, successNoSave, reject) => { var matches = getJoins2(doc).Where(join => id1FromJoin(join) == id1).ToArray(); if (matches.Length > 0) { duplicateJoin2 = matches[0]; return(reject()); } mutateUpdate2(doc); return(successSave(id2)); }, (id1Again, doc) => { mutateRollback2(doc); return(true); }, () => joinAlreadyExist(duplicateJoin2), doc2DoesNotExist, repo); //parallel.AddTaskUpdate(id2, // mutateUpdate2, // mutateRollback2, // doc2DoesNotExist, // repo); parallel.AddTaskCreate(id, document, () => joinIdAlreadyExist(), repo); var result = await parallel.ExecuteAsync( () => onSuccess(), (failureResult) => failureResult); return(result); }
internal static Task <TResult> CreateAsync <TResult>(Guid processId, Guid processStageId, Guid actorId, Guid resourceId, Type resourceType, DateTime createdOn, Process.ProcessStageResource[] resources, Guid?previousStepId, DateTime?confirmedWhen, Guid?confirmedBy, Guid [] lookupActorIds, Func <TResult> onSuccess, Func <TResult> onAlreadyExists) { return(AzureStorageRepository.Connection( azureStorageRepository => { var rollback = new RollbackAsync <TResult>(); var resourceTypeString = resourceType.AssemblyQualifiedName; var processDocument = new ProcessDocument() { ProcessStage = processStageId, Resource = resourceId, ResourceType = resourceTypeString, CreatedOn = createdOn, Owner = actorId, ConfirmedBy = confirmedBy, PreviousStep = previousStepId, ConfirmedWhen = confirmedWhen, }; processDocument.SetResources(resources); rollback.AddTaskCreate(processId, processDocument, onAlreadyExists, azureStorageRepository); foreach (var lookupActorId in lookupActorIds.Distinct()) { rollback.AddTaskCreateOrUpdate <TResult, Documents.ProcessStepActorLookupDocument>(lookupActorId, resourceTypeString, (created, lookupDoc) => lookupDoc.AddLookupDocumentId(processId), actorDoc => actorDoc.RemoveLookupDocumentId(processId), azureStorageRepository); } rollback.AddTaskCreateOrUpdate <TResult, Documents.ProcessStepResourceLookupDocument>(resourceId, resourceTypeString, (created, lookupDoc) => lookupDoc.AddLookupDocumentId(processId), actorDoc => actorDoc.RemoveLookupDocumentId(processId), azureStorageRepository); bool[] updates = resources .Select( resource => { if (!resource.resourceId.HasValue) { return true; } rollback.AddTaskCreateOrUpdate <TResult, Documents.ProcessStepResourceKeyLookupDocument>( resource.resourceId.Value, resource.type.AssemblyQualifiedName, (created, lookupDoc) => lookupDoc.AddLookupDocumentId(processId), lookupDoc => lookupDoc.RemoveLookupDocumentId(processId), azureStorageRepository); return true; }) .ToArray(); return rollback.ExecuteAsync(onSuccess); })); }
public static async Task <TRollback> ExecuteDeleteJoinAsync <TRollback, TDocument>(this RollbackAsync <Guid?, TRollback> rollback, Func <TRollback> onSuccess, AzureStorageRepository repo) where TDocument : class, ITableEntity { var result = await await rollback.ExecuteAsync <Task <TRollback> >( async (joinIds) => { var joinId = joinIds.First(joinIdCandidate => joinIdCandidate.HasValue); if (!joinId.HasValue) { return(onSuccess()); } return(await repo.DeleteIfAsync <TDocument, TRollback>(joinId.Value, async(doc, delete) => { await delete(); return onSuccess(); }, () => { // TODO: Log data inconsistency return onSuccess(); })); }, (failureResult) => failureResult.ToTask()); return(result); }
public static async Task <TRollback> ExecuteAsync <TRollback>(this RollbackAsync <TRollback> rollback, Func <TRollback> onSuccess) { return(await rollback.ExecuteAsync(onSuccess, r => r)); }