Backend/e-suite.Modules.SequenceManager/e-Suite.Modules.SequenceManager/SequenceManager.cs

202 lines
8.0 KiB
C#

using System.Diagnostics;
using System.Linq.Expressions;
using e_suite.API.Common;
using e_suite.API.Common.exceptions;
using e_suite.API.Common.models;
using e_suite.API.Common.repository;
using e_suite.Database.Audit;
using e_suite.Utilities.Pagination;
using eSuite.Core.Clock;
using eSuite.Core.Miscellaneous;
namespace e_suite.Modules.SequenceManager;
public class SequenceManager : ISequenceManager
{
private readonly ISequenceManagerRepository _sequenceManagerRepository;
private readonly IClock _clock;
public SequenceManager(ISequenceManagerRepository sequenceManagerRepository, IClock clock)
{
_sequenceManagerRepository = sequenceManagerRepository;
_clock = clock;
}
public async Task<Sequence> GetSequence(IGeneralIdRef generalIdRef, CancellationToken cancellationToken)
{
var sequence = await _sequenceManagerRepository.GetSequenceById(generalIdRef, cancellationToken);
if (sequence == null)
throw new NotFoundException();
if (sequence.Deleted)
throw new NotFoundException();
var sequenceModel = new Sequence
{
GeneralIdRef = new GeneralIdRef
{
Guid = sequence.Guid,
Id = sequence.Id
},
Name = sequence.Name,
Pattern = sequence.Pattern,
Increment = sequence.Increment,
Seed = sequence.Seed,
RolloverType = sequence.Rollover
};
return sequenceModel;
}
public async Task<IPaginatedData<ReadSequence>> GetSequences(Paging paging, CancellationToken cancellationToken)
{
var sequences = _sequenceManagerRepository.GetSequenceList();
var paginatedData = await PaginatedData.Paginate(sequences, paging,
KeySelector, cancellationToken);
var paginatedResult = new PaginatedData<ReadSequence>()
{
Count = paginatedData.Count,
Page = paginatedData.Page,
PageSize = paginatedData.PageSize,
Data = paginatedData.Data.Select(x => new ReadSequence
{
Id = x.Id,
Guid = x.Guid,
Name = x.Name
})
};
return paginatedResult;
}
private Expression<Func<Database.Core.Tables.Sequences.Sequence, object>> KeySelector(string? sortKey)
{
return sortKey?.ToLowerInvariant() switch
{
"id" => x => x.Id,
"guid" => x => x.Guid,
_ => x => x.Name
};
}
public async Task CreateSequence(AuditUserDetails auditUserDetails, NewSequence sequence, CancellationToken cancellationToken)
{
await _sequenceManagerRepository.TransactionAsync(async () =>
{
var existingSequence = sequence.Guid == null
? null
: await _sequenceManagerRepository.GetSequenceById(new GeneralIdRef
{
Guid = sequence.Guid
}, cancellationToken);
if (existingSequence != null && !existingSequence.Deleted)
throw new ExistsException($"Sequence with guid '{sequence.Guid}' already exists");
if (existingSequence == null)
{
existingSequence = await _sequenceManagerRepository.GetSequenceByName(sequence.Name, cancellationToken);
if (existingSequence != null && !existingSequence.Deleted)
throw new ExistsException($"Sequence with name '{sequence.Name}' already exists");
}
existingSequence ??= new Database.Core.Tables.Sequences.Sequence
{
Guid = sequence.Guid ?? Guid.NewGuid()
};
existingSequence.Name = sequence.Name;
existingSequence.Seed = sequence.Seed;
existingSequence.Increment = sequence.Increment;
existingSequence.Pattern = sequence.Pattern;
existingSequence.Rollover = sequence.RolloverType;
if (existingSequence.Deleted)
{
existingSequence.Deleted = false;
await _sequenceManagerRepository.EditSequence(auditUserDetails, existingSequence, cancellationToken);
}
else
{
await _sequenceManagerRepository.AddSequence(auditUserDetails, existingSequence, cancellationToken);
}
});
}
public async Task EditSequence(AuditUserDetails auditUserDetails, Sequence editSequence, CancellationToken cancellationToken)
{
await _sequenceManagerRepository.TransactionAsync(async () =>
{
var existingSequence =
await _sequenceManagerRepository.GetSequenceById(editSequence.GeneralIdRef!, cancellationToken);
if (existingSequence == null || existingSequence.Deleted)
throw new NotFoundException("A sequence with this Id doesn't exist");
var identicalNameSequence =
await _sequenceManagerRepository.GetSequenceByName(editSequence.Name, cancellationToken);
if (identicalNameSequence != null && (identicalNameSequence.Id != editSequence.GeneralIdRef!.Id &&
identicalNameSequence.Guid != editSequence.GeneralIdRef.Guid))
throw new ExistsException($"Sequence with name '{editSequence.Name}' already exists");
existingSequence.Name = editSequence.Name;
existingSequence.Increment = editSequence.Increment;
existingSequence.Seed = editSequence.Seed;
existingSequence.Pattern = editSequence.Pattern;
existingSequence.Rollover = editSequence.RolloverType;
await _sequenceManagerRepository.EditSequence(auditUserDetails, existingSequence, cancellationToken);
});
}
public async Task DeleteSequence(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, CancellationToken cancellationToken)
{
await _sequenceManagerRepository.TransactionAsync(async () =>
{
var existingSequence = await _sequenceManagerRepository.GetSequenceById(generalIdRef, cancellationToken);
if (existingSequence == null || existingSequence.Deleted)
throw new NotFoundException("A sequence with this Id doesn't exist");
existingSequence.Deleted = true;
await _sequenceManagerRepository.EditSequence(auditUserDetails, existingSequence, cancellationToken);
});
}
public async Task<IEnumerable<string>> NextValue(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef,
CancellationToken cancellationToken)
{
return await NextValue( auditUserDetails, generalIdRef, 1, cancellationToken).ConfigureAwait(false);
}
public async Task<IEnumerable<string>> NextValue(AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, int number, CancellationToken cancellationToken)
{
return await _sequenceManagerRepository.TransactionAsync(async () =>
{
var existingSequence = await _sequenceManagerRepository.GetSequenceById(generalIdRef, cancellationToken);
if (existingSequence == null || existingSequence.Deleted)
throw new NotFoundException("A sequence with this Id doesn't exist");
var result = new List<string>();
var stopwatch = Stopwatch.StartNew();
while (result.Count < number)
{
if (stopwatch.ElapsedMilliseconds > 2000)
throw new TimeoutException($"Took more than 2 seconds to create count list. Created {result.Count} values in the available time");
cancellationToken.ThrowIfCancellationRequested();
result.Add(SequenceNumberBuilder.GetNextSequenceNumber(existingSequence, _clock));
}
await _sequenceManagerRepository.EditSequence(auditUserDetails, existingSequence, cancellationToken);
return result;
});
}
}