Improved results handling in service layer

This commit is contained in:
2026-09-11 10:32:51 +02:00
parent 66f720a20b
commit a15b25248d
11 changed files with 87 additions and 103 deletions
@@ -38,9 +38,8 @@ public sealed class CommunicationsService(IDbContextFactory<ApplicationDbContext
CreatedAt = DateTime.UtcNow
});
return await context.SaveChangesAsync(cancellationToken) > 0
? Result.Ok(invite.Map())
: Result.Fail<Invite>(CreateError.New);
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New)
.ToResult(invite.Map());
}));
public async ValueTask<Result<Invite[]>> GetInvitesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
@@ -64,9 +63,8 @@ public sealed class CommunicationsService(IDbContextFactory<ApplicationDbContext
var invite = await context.Invites.AsNoTracking().FirstOrDefaultAsync(i => i.Recipient == applicantUserId, cancellationToken);
return invite is not null
? Result.Ok(invite.Map())
: Result.Fail<Invite>(NotFoundError.New);
return Result.FailIf(invite is null, NotFoundError.New)
.ToResult(invite!.Map());
}));
public async ValueTask<Result<Invite[]>> GetApplicantInvitesAsync(Guid applicantUserId, CancellationToken cancellationToken = default) =>
@@ -47,7 +47,7 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
context.Evidences.Add(evidence);
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New);
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
}));
public async ValueTask<Result> RecordIndicatorActualAmountAsync(string indicatorIdHash, decimal amount, Guid userId, CancellationToken cancellationToken = default) =>
@@ -66,7 +66,7 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
.SetProperty(f => f.ActualAmount, amount)
.SetProperty(f => f.CreatedBy, userId), cancellationToken);
return Result.FailIf(changedTotal <= 0, UpdateError.New);
return Result.OkIf(changedTotal > 0, UpdateError.New);
}));
public async ValueTask<Result<Indicator[]>> GetIndicatorsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
@@ -119,7 +119,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
CreatedAt = DateTime.UtcNow
});
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.Create("No record could be created."));
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0,
CreateError.Create("No record could be created."));
}));
public async ValueTask<Result> CreateIndicatorAsync(CreateIndicatorRequest request, Guid userId, CancellationToken cancellationToken = default) =>
@@ -142,7 +143,7 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
CreatedAt = DateTime.UtcNow
});
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New);
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
}));
public async ValueTask<Result<Indicator>> GetIndicatorAsync(string indicatorId, CancellationToken cancellationToken) =>
@@ -158,9 +159,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
var indicator = await context.Indicators.AsNoTracking().FirstOrDefaultAsync(i => i.Id == decodeResult.Value, cancellationToken);
return indicator is not null
? Result.Ok(indicator.Map())
: Result.Fail(NotFoundError.New);
return Result.FailIf(indicator is null, NotFoundError.New)
.ToResult(indicator!.Map());
}));
public async ValueTask<Result<Domain.Models.Evidence>> GetEvidenceAsync(string evidenceId, CancellationToken cancellationToken = default) =>
@@ -176,9 +176,8 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
var evidence = await context.Evidences.AsNoTracking().FirstOrDefaultAsync(e => e.Id == decodeResult.Value, cancellationToken);
return evidence is not null
? Result.Ok(evidence.Map())
: Result.Fail<Domain.Models.Evidence>(NotFoundError.New);
return Result.FailIf(evidence is null, NotFoundError.New)
.ToResult(evidence!.Map());
}));
public async ValueTask<Result<Domain.Models.Evidence[]>> GetMilestoneEvidencesAsync(string milestoneIdHash, CancellationToken cancellationToken = default) =>
@@ -237,6 +236,6 @@ public sealed class EvidenceService(IDbContextFactory<ApplicationDbContext> cont
.SetProperty(f => f.UpdatedBy, userId)
.SetProperty(f => f.UpdatedAt, DateTime.UtcNow), cancellationToken);
return Result.FailIf(changedTotal <= 0, UpdateError.New);
return Result.OkIf(changedTotal > 0, UpdateError.New);
}));
}
@@ -57,7 +57,7 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
CreatedAt = DateTime.UtcNow
});
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New);
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
}));
public async ValueTask<Result> CreateDisbursementAsync(CreateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default) =>
@@ -78,7 +78,7 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
CreatedAt = DateTime.UtcNow
});
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New);
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
}));
public async ValueTask<Result> ApproveDisbursementAsync(string disbursementIdHash, Guid userId, CancellationToken cancellationToken = default) =>
@@ -98,7 +98,7 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
.SetProperty(f => f.UpdatedBy, userId)
.SetProperty(f => f.UpdatedAt, DateTime.UtcNow), cancellationToken);
return Result.FailIf(changedTotal <= 0, UpdateError.New);
return Result.OkIf(changedTotal > 0, UpdateError.New);
}));
public async ValueTask<Result<Disbursement>> GetDisbursementAsync(string disbursementIdHash, CancellationToken cancellationToken) =>
@@ -115,9 +115,8 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
var disbursement = await context.Disbursements.AsNoTracking()
.FirstOrDefaultAsync(d => d.Id == decodeResult.Value, cancellationToken);
return disbursement is not null
? Result.Ok(disbursement.Map())
: Result.Fail<Disbursement>(NotFoundError.New);
return Result.FailIf(disbursement is null, NotFoundError.New)
.ToResult(disbursement!.Map());
}));
public async ValueTask<Result<Risk>> GetRiskAsync(string riskIdHash, CancellationToken cancellationToken = default) =>
@@ -134,9 +133,8 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
var risk = await context.Risks.AsNoTracking()
.FirstOrDefaultAsync(r => r.Id == decodeResult.Value, cancellationToken);
return risk is not null
? Result.Ok(risk.Map())
: Result.Fail<Risk>(NotFoundError.New);
return Result.FailIf(risk is null, NotFoundError.New)
.ToResult(risk!.Map());
}));
public async ValueTask<Result> UpdateRiskAsync(UpdateRiskRequest request, CancellationToken cancellationToken = default) =>
@@ -152,7 +150,7 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
.SetProperty(u => u.Likelihood, request.Likelihood)
.SetProperty(u => u.Impact, request.Impact), cancellationToken);
return Result.FailIf(changedTotal <= 0, UpdateError.New);
return Result.OkIf(changedTotal > 0, UpdateError.New);
}));
public async ValueTask<Result> UpdateDisbursementAsync(UpdateDisbursementRequest request, Guid userId, CancellationToken cancellationToken = default) =>
@@ -168,6 +166,6 @@ public sealed class ExecutionService(IDbContextFactory<ApplicationDbContext> con
.SetProperty(d => d.UpdatedAt, DateTime.UtcNow)
.SetProperty(d => d.UpdatedBy, userId), cancellationToken);
return Result.FailIf(changedTotal <= 0, UpdateError.New);
return Result.OkIf(changedTotal > 0, UpdateError.New);
}));
}
@@ -77,9 +77,8 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
var organisation = await context.Organisations.AsNoTracking()
.FirstOrDefaultAsync(o => o.Id == decodeResult.Value, cancellationToken);
return organisation is not null
? Result.Ok(organisation.Map())
: Result.Fail(NotFoundError.New);
return Result.FailIf(organisation is null, NotFoundError.New)
.ToResult(organisation!.Map());
}));
public async ValueTask<Result<Instrument[]>> GetInstrumentsAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
@@ -148,7 +147,7 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
CreatedAt = DateTime.UtcNow
});
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New);
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
}));
public async ValueTask<Result<Organisation>> UpdateOrganisationAsync(UpdateOrganisationRequest request, CancellationToken cancellationToken = default) =>
@@ -164,7 +163,7 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
.SetProperty(u => u.Email, request.Email.ToLower(CultureInfo.InvariantCulture).Clean())
.SetProperty(u => u.Type, request.Type), cancellationToken);
return Result.FailIf(changedTotal <= 0, UpdateError.New);
return Result.OkIf(changedTotal > 0, UpdateError.New);
}));
public async ValueTask<Result> CreatePortfolioAsync(CreatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
@@ -193,7 +192,7 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
Description = request.Description.Humanize(LetterCasing.Sentence).Trim()
});
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New);
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
}));
public async ValueTask<Result> UpdatePortfolioAsync(UpdatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
@@ -211,7 +210,7 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
.SetProperty(u => u.OwnedBy, request.OwnerId)
.SetProperty(u => u.Description, request.Description.Humanize(LetterCasing.Sentence).Trim()), cancellationToken);
return Result.FailIf(changedTotal <= 0, UpdateError.Create("Nothing was saved, no change detected."));
return Result.OkIf(changedTotal > 0, UpdateError.Create("Nothing was saved, no change detected."));
}));
public async ValueTask<Result<Programme[]>> GetPortfolioProgrammesAsync(string portfolioIdHash, CancellationToken cancellationToken = default) =>
@@ -247,8 +246,7 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
var portfolio = await context.Portfolios.AsNoTracking()
.FirstOrDefaultAsync(p => p.Id == decodeResult.Value, cancellationToken);
return portfolio is not null
? Result.Ok(portfolio.Map())
: Result.Fail(NotFoundError.New);
return Result.FailIf(portfolio is null, NotFoundError.New)
.ToResult(portfolio!.Map());
}));
}
@@ -38,9 +38,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
var contract = await context.Contracts.AsNoTracking()
.FirstOrDefaultAsync(c => c.Id == decodeResult.Value, cancellationToken);
return contract is not null
? Result.Ok(contract.Map())
: Result.Fail<Contract>(NotFoundError.New);
return Result.FailIf(contract is null, NotFoundError.New)
.ToResult(contract!.Map());
}));
public async ValueTask<Result<Budget[]>> GetBudgetsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
@@ -71,9 +70,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
var budget = await context.Budgets.AsNoTracking()
.FirstOrDefaultAsync(b => b.Id == decodeResult.Value, cancellationToken);
return budget is not null
? Result.Ok(budget.Map())
: Result.Fail<Budget>(NotFoundError.New);
return Result.FailIf(budget is null, NotFoundError.New)
.ToResult(budget!.Map());
}));
public async ValueTask<Result<Award[]>> GetAwardsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
@@ -103,9 +101,8 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
var award = await context.Awards.AsNoTracking().FirstOrDefaultAsync(a => a.Id == decodeResult.Value, cancellationToken);
return award is not null
? Result.Ok(award.Map())
: Result.Fail<Award>(NotFoundError.New);
return Result.FailIf(award is null, NotFoundError.New)
.ToResult(award!.Map());
}));
public async ValueTask<Result> ExecuteContractAsync(ExecuteContractRequest request, Guid userId, CancellationToken cancellationToken = default) =>
@@ -121,7 +118,7 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
.SetProperty(u => u.CreatedBy, userId)
.SetProperty(u => u.Status, ContractStatus.Active), cancellationToken);
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, UpdateError.New);
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, UpdateError.New);
}));
public async ValueTask<Result> CreateContractAsync(CreateContractRequest request, Guid userId, CancellationToken cancellationToken = default) =>
@@ -148,7 +145,7 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
context.Contracts.Add(contract);
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New);
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
}));
public async ValueTask<Result> CreateBudgetAsync(CreateBudgetRequest request, Guid userId, CancellationToken cancellationToken = default) =>
@@ -173,7 +170,7 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
context.Budgets.Add(budget);
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New);
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
}));
public async ValueTask<Result> CreateAwardAsync(CreateAwardRequest request, Guid userId, CancellationToken cancellationToken = default) =>
@@ -202,6 +199,6 @@ public sealed class GrantsService(IDbContextFactory<ApplicationDbContext> contex
context.Awards.Add(award);
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New);
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
}));
}
@@ -25,7 +25,7 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
.SetProperty(p => p.UpdatedBy, userId)
.SetProperty(p => p.UpdatedAt, DateTime.UtcNow), cancellationToken);
return Result.FailIf(changedTotal <= 0, UpdateError.Create("No changes detected, update cancelled."));
return Result.OkIf(changedTotal > 0, UpdateError.Create("No changes detected, update cancelled."));
}));
public async ValueTask<Result<Project[]>> GetProjectsAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
@@ -55,9 +55,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
var project = await context.Projects.AsNoTracking()
.FirstOrDefaultAsync(p => p.Id == decodeResult.Value, cancellationToken);
return project is not null
? Result.Ok(project.Map())
: Result.Fail<Project>(NotFoundError.Create());
return Result.FailIf(project is null, NotFoundError.New)
.ToResult(project!.Map());
}));
public async ValueTask<Result<Domain.Models.Activity[]>> GetActivitiesAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
@@ -105,7 +104,7 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
CreatedAt = DateTime.UtcNow
});
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0,
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0,
CreateError.Create("No changes detected, update cancelled."));
}));
@@ -135,7 +134,7 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
CreatedAt = DateTime.UtcNow
});
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0,
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0,
CreateError.Create("No record was created."));
}));
@@ -190,9 +189,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
var milestone = await context.Milestones.AsNoTracking()
.FirstOrDefaultAsync(m => m.Id == decodeResult.Value, cancellationToken);
return milestone is not null
? Result.Ok(milestone.Map())
: Result.Fail<Milestone>(NotFoundError.Create());
return Result.FailIf(milestone is null, NotFoundError.New)
.ToResult(milestone!.Map());
}));
public async ValueTask<Result<Milestone[]>> GetMilestonesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
@@ -226,7 +224,7 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
.SetProperty(u => u.UpdatedBy, userId)
.SetProperty(u => u.UpdatedAt, DateTime.UtcNow), cancellationToken);
return Result.FailIf(changedTotal <= 0, UpdateError.Create("No changes detected, update cancelled."));
return Result.OkIf(changedTotal > 0, UpdateError.Create("No changes detected, update cancelled."));
}));
public async ValueTask<Result> UpdateProjectAsync(UpdateProjectRequest request, Guid userId, CancellationToken cancellationToken = default) =>
@@ -245,7 +243,7 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
.SetProperty(u => u.Sector, request.Sector)
.SetProperty(u => u.ProjectType, request.ProjectType), cancellationToken);
return Result.FailIf(changedTotal <= 0, UpdateError.Create("No changes detected, update cancelled."));
return Result.OkIf(changedTotal > 0, UpdateError.Create("No changes detected, update cancelled."));
}));
public async ValueTask<Result<Domain.Models.Activity>> GetActivityAsync(string activityIdHash, CancellationToken cancellationToken = default) =>
@@ -262,9 +260,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
var activity = await context.Activities.AsNoTracking()
.FirstOrDefaultAsync(a => a.Id == decodeResult.Value, cancellationToken);
return activity is not null
? Result.Ok(activity.Map())
: Result.Fail<Domain.Models.Activity>(NotFoundError.New);
return Result.FailIf(activity is null, NotFoundError.New)
.ToResult(activity!.Map());
}));
public async ValueTask<Result<Risk[]>> GetProjectRisksAsync(string projectIdHash, CancellationToken cancellationToken = default) =>
@@ -309,7 +306,7 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
Status = ApprovalStatus.Pending
});
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New);
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
}));
public async ValueTask<Result> UpdateProgrammeAsync(UpdateProgrammeRequest request, Guid userId, CancellationToken cancellationToken = default) =>
@@ -328,7 +325,7 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
.SetProperty(u => u.UpdatedBy, userId)
.SetProperty(u => u.UpdatedAt, DateTime.UtcNow), cancellationToken);
return Result.FailIf(changedTotal <= 0, UpdateError.Create("No changes detected, update cancelled."));
return Result.OkIf(changedTotal > 0, UpdateError.Create("No changes detected, update cancelled."));
}));
public async ValueTask<Result<Programme>> GetProgrammeAsync(string programmeIdHash, CancellationToken cancellationToken = default) =>
@@ -343,9 +340,8 @@ public sealed class ProjectService(IDbContextFactory<ApplicationDbContext> conte
var programme = await context.Programmes.FirstOrDefaultAsync(p => p.Id == decodeResult.Value, cancellationToken);
return programme is not null
? Result.Ok(programme.Map())
: Result.Fail(NotFoundError.New);
return Result.FailIf(programme is null, NotFoundError.New)
.ToResult(programme!.Map());
}));
public async ValueTask<Result<Programme[]>> GetProgrammesAsync(Pagination pagination, CancellationToken cancellationToken = default) =>
@@ -33,9 +33,9 @@ public sealed class BrowserLocalStorageService(ProtectedLocalStorage storage)
{
var retrieval = await storage.GetAsync<string>(key);
return retrieval.Success && !string.IsNullOrWhiteSpace(retrieval.Value)
? Result.Ok(retrieval.Value)
: Result.Fail(NotFoundError.Create($"Could not find object by key {key}"));
return Result.FailIf(!retrieval.Success && string.IsNullOrWhiteSpace(retrieval.Value),
NotFoundError.Create($"Could not find object by key {key}"))
.ToResult(retrieval.Value!);
}));
public async ValueTask<Result<TValue>> GetAsync<TValue>(string key) where TValue : class =>
@@ -43,8 +43,8 @@ public sealed class BrowserLocalStorageService(ProtectedLocalStorage storage)
{
var retrieval = await storage.GetAsync<TValue>(key);
return retrieval.Success && retrieval.Value is not null
? Result.Ok(retrieval.Value)
: Result.Fail(NotFoundError.Create($"Could not find object by key {key}"));
return Result.FailIf(!retrieval.Success && retrieval.Value is null,
NotFoundError.Create($"Could not find object by key {key}"))
.ToResult(retrieval.Value!);
}));
}
@@ -31,17 +31,18 @@ public sealed partial class HashService(IHashids hasher) : IService
return Result.Ok(Convert.ToHexString(bytes).ToLowerInvariant());
}
public Result<string> HashEncodeHex(string input) => string.IsNullOrWhiteSpace(input) || !Patterns.HexHashRegex.IsMatch(input)
? Result.Fail<string>(ValidationError.Create("Input must be a valid hexadecimal string."))
: Result.Ok(hasher.EncodeHex(input));
public Result<string> HashEncodeHex(string input) =>
Result.FailIf(string.IsNullOrWhiteSpace(input) || !Patterns.HexHashRegex.IsMatch(input),
ValidationError.Create("Input must be a valid hexadecimal string."))
.ToResult(hasher.EncodeHex(input));
public Result<string> HashEncodeIntId(int id) => id < 0
? Result.Fail<string>(ValidationError.Create("Id cannot be negative."))
: Result.Ok(hasher.Encode(id));
public Result<string> HashEncodeIntId(int id) =>
Result.FailIf(id < 0, ValidationError.Create("Id cannot be negative."))
.ToResult(hasher.Encode(id));
public Result<string> HashEncodeLongId(long id) => id < 0
? Result.Fail<string>(ValidationError.Create("Id cannot be negative."))
: Result.Ok(hasher.EncodeLong(id));
public Result<string> HashEncodeLongId(long id) =>
Result.FailIf(id < 0, ValidationError.Create("Id cannot be negative."))
.ToResult(hasher.EncodeLong(id));
public Result<int> DecodeIntIdHash(string hash)
{
@@ -50,9 +51,8 @@ public sealed partial class HashService(IHashids hasher) : IService
int[] decoded = hasher.Decode(hash);
return decoded.Length == 1
? Result.Ok(decoded[0]) :
Result.Fail<int>(ValidationError.Create("Invalid or modified Int hash token."));
return Result.FailIf(decoded.Length <= 0, ValidationError.Create("Invalid or modified Int hash token."))
.ToResult(decoded[0]);
}
public Result<long> DecodeLongIdHash(string hash)
@@ -62,8 +62,8 @@ public sealed partial class HashService(IHashids hasher) : IService
long[] decoded = hasher.DecodeLong(hash);
return decoded.Length == 1 ? Result.Ok(decoded[0]) :
Result.Fail<long>(ValidationError.Create("Invalid or modified Long hash token."));
return Result.FailIf(decoded.Length <= 0, ValidationError.Create("Invalid or modified Long hash token."))
.ToResult(decoded[0]);
}
public async Task<Result<string>> DecodeHexHash(string hex) =>
@@ -71,8 +71,7 @@ public sealed partial class HashService(IHashids hasher) : IService
{
string decoded = hasher.DecodeHex(hex);
return string.IsNullOrEmpty(decoded)
? Result.Fail<string>(ValidationError.Create("Invalid or corrupted hex hash."))
: Result.Ok(decoded);
return Result.FailIf(string.IsNullOrEmpty(decoded), ValidationError.Create("Invalid or corrupted hex hash."))
.ToResult(decoded);
}));
}
@@ -15,6 +15,6 @@ public sealed class IdentityService(IDbContextFactory<ApplicationDbContext> cont
var userExistsAndActive = await context.Users
.AnyAsync(u => u.Id == userId && u.Status == ActivityStatus.Active, cancellationToken);
return Result.FailIf(!userExistsAndActive, NotFoundError.Create());
return Result.OkIf(userExistsAndActive, NotFoundError.Create());
}));
}
@@ -29,16 +29,16 @@ public sealed class TokenService(ISecurityConnectApi connectApi, IOptions<Securi
{
var tokenResponse = JsonSerializer.Deserialize<Domain.Security.Models.TokenResponse>(contentRaw);
return !string.IsNullOrWhiteSpace(tokenResponse?.AccessToken)
? Result.Ok(tokenResponse)
: Result.Fail<Domain.Security.Models.TokenResponse>(NotFoundError.Create("Authentication succeeded, but no access token was found in the response payload."));
return Result.FailIf(string.IsNullOrWhiteSpace(tokenResponse?.AccessToken),
NotFoundError.Create("Authentication succeeded, but no access token was found in the response payload."))
.ToResult(tokenResponse!);
}
return await Result.Try((Func<ValueTask<Result<Domain.Security.Models.TokenResponse>>>)(async () =>
{
var errorResult = JsonSerializer.Deserialize<TokenErrorResponse>(contentRaw);
return Result.FailIf(errorResult != null,
return Result.OkIf(errorResult is not null,
CreateError.Create($"{errorResult!.Error}: {errorResult.ErrorDescription}"));
}));
}));
@@ -32,7 +32,7 @@ public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextF
context.Users.Update(user);
}
return Result.FailIf(await context.SaveChangesAsync(cancellationToken) <= 0, CreateError.New);
return Result.OkIf(await context.SaveChangesAsync(cancellationToken) > 0, CreateError.New);
}));
public async ValueTask<Result<User[]>> GetUsersAsync(Pagination pagination, UserFilterRequest request, CancellationToken cancellationToken = default) =>
@@ -74,7 +74,7 @@ public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextF
.Where(f => f.Id == userId)
.ExecuteUpdateAsync(f => f.SetProperty(u => u.Status, status), cancellationToken);
return Result.FailIf(changedTotal <= 0, UpdateError.New);
return Result.OkIf(changedTotal > 0, UpdateError.New);
}));
public async ValueTask<Result<User>> GetUserAsync(Guid userId, CancellationToken cancellationToken) =>
@@ -85,8 +85,7 @@ public sealed class UserService(IDbContextFactory<ApplicationDbContext> contextF
var user = await context.Users.AsNoTracking()
.FirstOrDefaultAsync(f => f.Id == userId, cancellationToken);
return user is not null
? Result.Ok(user.Map())
: Result.Fail(NotFoundError.New);
return Result.FailIf(user is null, NotFoundError.New)
.ToResult(user!.Map());
}));
}