refactor(dotnet): normalize workspace and approval inputs
This commit is contained in:
@@ -10,18 +10,39 @@ namespace QuantEngine.Application.Services
|
||||
{
|
||||
private readonly IWorkspaceRepository _repository;
|
||||
|
||||
public ApprovalService(IWorkspaceRepository repository)
|
||||
public ApprovalService(IWorkspaceRepository repository)
|
||||
{
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
public Task<IEnumerable<WorkspaceApproval>> GetApprovalsAsync() => _repository.GetApprovalsAsync();
|
||||
public Task<WorkspaceApproval?> GetApprovalAsync(string domain, string targetRef)
|
||||
=> _repository.GetApprovalAsync(RequireValue(domain, nameof(domain)), RequireValue(targetRef, nameof(targetRef)));
|
||||
public Task<bool> UpsertApprovalAsync(WorkspaceApproval approval)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(approval);
|
||||
return _repository.UpsertApprovalAsync(approval);
|
||||
}
|
||||
|
||||
public Task<IEnumerable<WorkspaceLock>> GetLocksAsync() => _repository.GetLocksAsync();
|
||||
public Task<WorkspaceLock?> GetLockAsync(string domain, string targetRef)
|
||||
=> _repository.GetLockAsync(RequireValue(domain, nameof(domain)), RequireValue(targetRef, nameof(targetRef)));
|
||||
public Task<bool> AcquireLockAsync(WorkspaceLock @lock)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(@lock);
|
||||
return _repository.AcquireLockAsync(@lock);
|
||||
}
|
||||
public Task<bool> ReleaseLockAsync(string domain, string targetRef)
|
||||
=> _repository.ReleaseLockAsync(RequireValue(domain, nameof(domain)), RequireValue(targetRef, nameof(targetRef)));
|
||||
|
||||
private static string RequireValue(string value, string parameterName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
_repository = repository;
|
||||
throw new ArgumentException("Value is required.", parameterName);
|
||||
}
|
||||
|
||||
public Task<IEnumerable<WorkspaceApproval>> GetApprovalsAsync() => _repository.GetApprovalsAsync();
|
||||
public Task<WorkspaceApproval?> GetApprovalAsync(string domain, string targetRef) => _repository.GetApprovalAsync(domain, targetRef);
|
||||
public Task<bool> UpsertApprovalAsync(WorkspaceApproval approval) => _repository.UpsertApprovalAsync(approval);
|
||||
|
||||
public Task<IEnumerable<WorkspaceLock>> GetLocksAsync() => _repository.GetLocksAsync();
|
||||
public Task<WorkspaceLock?> GetLockAsync(string domain, string targetRef) => _repository.GetLockAsync(domain, targetRef);
|
||||
public Task<bool> AcquireLockAsync(WorkspaceLock @lock) => _repository.AcquireLockAsync(@lock);
|
||||
public Task<bool> ReleaseLockAsync(string domain, string targetRef) => _repository.ReleaseLockAsync(domain, targetRef);
|
||||
return value.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,22 +11,39 @@ namespace QuantEngine.Application.Services
|
||||
private readonly IWorkspaceRepository _repository;
|
||||
private readonly IPostgresqlHistoryStore _historyStore;
|
||||
|
||||
public WorkspaceService(IWorkspaceRepository repository, IPostgresqlHistoryStore historyStore)
|
||||
public WorkspaceService(IWorkspaceRepository repository, IPostgresqlHistoryStore historyStore)
|
||||
{
|
||||
_repository = repository;
|
||||
_historyStore = historyStore;
|
||||
}
|
||||
|
||||
public Task<IEnumerable<Setting>> GetSettingsAsync() => _repository.GetSettingsAsync();
|
||||
public Task<Setting?> GetSettingByKeyAsync(string key) => _repository.GetSettingByKeyAsync(RequireValue(key, nameof(key)));
|
||||
public Task<bool> UpsertSettingAsync(Setting setting)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(setting);
|
||||
return _repository.UpsertSettingAsync(setting);
|
||||
}
|
||||
public Task<bool> DeleteSettingAsync(string key) => _repository.DeleteSettingAsync(RequireValue(key, nameof(key)));
|
||||
|
||||
public Task<IEnumerable<AccountSnapshot>> GetAccountSnapshotsAsync() => _repository.GetAccountSnapshotsAsync();
|
||||
public Task<bool> InsertAccountSnapshotsAsync(IEnumerable<AccountSnapshot> snapshots) => _repository.InsertAccountSnapshotsAsync(snapshots);
|
||||
public Task<bool> ClearAccountSnapshotsAsync() => _repository.ClearAccountSnapshotsAsync();
|
||||
|
||||
public Task<int> AppendHistoryAsync(string domain, IDictionary<string, object?> payload)
|
||||
=> _historyStore.AppendAsync(RequireValue(domain, nameof(domain)), payload);
|
||||
|
||||
public Task<IReadOnlyList<IDictionary<string, object?>>> ReadHistorySnapshotAsync(string domain, int limit = 500)
|
||||
=> _historyStore.SnapshotAsync(RequireValue(domain, nameof(domain)), Math.Clamp(limit, 1, 2000));
|
||||
|
||||
private static string RequireValue(string value, string parameterName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
_repository = repository;
|
||||
_historyStore = historyStore;
|
||||
throw new ArgumentException("Value is required.", parameterName);
|
||||
}
|
||||
|
||||
public Task<IEnumerable<Setting>> GetSettingsAsync() => _repository.GetSettingsAsync();
|
||||
public Task<Setting?> GetSettingByKeyAsync(string key) => _repository.GetSettingByKeyAsync(key);
|
||||
public Task<bool> UpsertSettingAsync(Setting setting) => _repository.UpsertSettingAsync(setting);
|
||||
public Task<bool> DeleteSettingAsync(string key) => _repository.DeleteSettingAsync(key);
|
||||
|
||||
public Task<IEnumerable<AccountSnapshot>> GetAccountSnapshotsAsync() => _repository.GetAccountSnapshotsAsync();
|
||||
public Task<bool> InsertAccountSnapshotsAsync(IEnumerable<AccountSnapshot> snapshots) => _repository.InsertAccountSnapshotsAsync(snapshots);
|
||||
public Task<bool> ClearAccountSnapshotsAsync() => _repository.ClearAccountSnapshotsAsync();
|
||||
|
||||
public Task<int> AppendHistoryAsync(string domain, IDictionary<string, object?> payload) => _historyStore.AppendAsync(domain, payload);
|
||||
public Task<IReadOnlyList<IDictionary<string, object?>>> ReadHistorySnapshotAsync(string domain, int limit = 500) => _historyStore.SnapshotAsync(domain, limit);
|
||||
return value.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
using Moq;
|
||||
using QuantEngine.Application.Services;
|
||||
using QuantEngine.Core.Interfaces;
|
||||
using QuantEngine.Core.Models;
|
||||
|
||||
namespace QuantEngine.Core.Tests;
|
||||
|
||||
public class WorkspaceApprovalServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task WorkspaceService_RejectsBlankHistoryDomain()
|
||||
{
|
||||
var service = new WorkspaceService(new Mock<IWorkspaceRepository>().Object, new Mock<IPostgresqlHistoryStore>().Object);
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentException>(() =>
|
||||
service.AppendHistoryAsync(" ", new Dictionary<string, object?>()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApprovalService_NormalizesLookupKeys()
|
||||
{
|
||||
var repo = new Mock<IWorkspaceRepository>(MockBehavior.Strict);
|
||||
repo.Setup(r => r.GetApprovalAsync("workflow", "target-1")).ReturnsAsync(new WorkspaceApproval());
|
||||
|
||||
var service = new ApprovalService(repo.Object);
|
||||
|
||||
var approval = await service.GetApprovalAsync(" workflow ", " target-1 ");
|
||||
|
||||
Assert.NotNull(approval);
|
||||
repo.VerifyAll();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ApprovalService_RejectsBlankLockTarget()
|
||||
{
|
||||
var service = new ApprovalService(new Mock<IWorkspaceRepository>().Object);
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentException>(() =>
|
||||
service.ReleaseLockAsync("workflow", " "));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user