Files
adas-core/adas-core.Infrastructure/Repositories/PumpAlarmStateRepository.cs
T

184 lines
10 KiB
C#

using adas_core.Application.Repositories.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.Pumps;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Driver;
namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Represents a MongoDB-based repository for <see cref="PumpAlarmState"/> entities, providing concrete data access functionality defined by the <see cref="IPumpAlarmStateRepository"/> contract.
/// </summary>
/// <!-- aidoc:v1 sig=86597ed -->
public class PumpAlarmStateRepository : MongoRepository<PumpAlarmState>, IPumpAlarmStateRepository
{
private readonly ApiSettings _apiSettings;
/// <summary>
/// Initializes a new instance of the <see cref="PumpAlarmStateRepository"/> class, which persists pump alarm state data, by storing the resolved <see cref="ApiSettings"/> and delegating MongoDB initialization to the base repository.
/// </summary>
/// <param name="apiSettings">The <see cref="IOptions{ApiSettings}"/> instance whose <see cref="IOptions{TOptions}.Value"/> supplies the <see cref="ApiSettings"/> used by the repository.</param>
/// <param name="database">The <see cref="IMongoDatabase"/> passed to the base constructor to provide the underlying MongoDB connection.</param>
/// <!-- aidoc:v1 sig=df28b3e body=12fddac -->
public PumpAlarmStateRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database)
: base(database)
{
_apiSettings = apiSettings.Value;
}
/// <summary>
/// Gets the collection name for the pump alarm state, returning the value configured in the API settings or the default "pump_alarm_state" when the configuration is not set.
/// </summary>
/// <returns>The configured collection name, or the default "pump_alarm_state" if the API setting is null.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=e7678e2 -->
public override string GetCollectionName()
{
return _apiSettings.PumpAlarmState ?? "pump_alarm_state";
}
/// <summary>
/// Creates the MongoDB indexes required by the <see cref="PumpAlarmState"/> collection: a unique compound index on <see cref="PumpAlarmState.DeviceId"/>, <see cref="PumpAlarmState.AlarmType"/>, and <see cref="PumpAlarmState.AlarmCodeMdc"/> (named <c>ux_device_alarm</c>), plus supporting indexes on <see cref="PumpAlarmState.DeviceId"/> and <see cref="PumpAlarmState.PatientId"/>.
/// </summary>
/// <!-- aidoc:v1 sig=4955da2 body=cfe5f4a -->
public override async Task CreateIndexes()
{
var indexModels = new List<CreateIndexModel<PumpAlarmState>>
{
// Clave única de alarma activa
new(
Builders<PumpAlarmState>.IndexKeys
.Ascending(x => x.DeviceId)
.Ascending(x => x.AlarmType)
.Ascending(x => x.AlarmCodeMdc),
new CreateIndexOptions { Unique = true, Name = "ux_device_alarm" }),
// Indexado por DeviceId
new(
Builders<PumpAlarmState>.IndexKeys.Ascending(x => x.DeviceId),
new CreateIndexOptions { Name = "ix_device" }),
// indexado por PatientId
new(
Builders<PumpAlarmState>.IndexKeys.Ascending(x => x.PatientId),
new CreateIndexOptions { Name = "ix_patientId" })
};
await Collection.Indexes.CreateManyAsync(indexModels);
}
/// <summary>
/// Retrieves the first active <see cref="PumpAlarmState"/> matching the specified device and optional alarm criteria.
/// The filter is always constrained by <paramref name="deviceId"/>, and additionally by <paramref name="alarmType"/> and <paramref name="alarmCodeMdc"/> when those values are provided.
/// Returns <c>null</c> when no matching alarm state is found.
/// </summary>
/// <param name="deviceId">The identifier of the device whose alarm state should be retrieved. Always applied to the query filter.</param>
/// <param name="alarmType">The optional alarm type used to further narrow the filter. When <c>null</c>, the alarm type is not applied.</param>
/// <param name="alarmCodeMdc">The optional alarm code (MDC) used to further narrow the filter. Ignored when <c>null</c>, empty, or whitespace.</param>
/// <returns>A <see cref="PumpAlarmState"/> instance if a matching record is found; otherwise, <c>null</c>.</returns>
/// <!-- aidoc:v1 sig=6935479 body=32e97b5 -->
public async Task<PumpAlarmState?> FindActiveAsync(string deviceId, PumpEnum.AlarmType? alarmType, string? alarmCodeMdc = null)
{
var filter = Builders<PumpAlarmState>.Filter.Eq(x => x.DeviceId, deviceId);
if (alarmType.HasValue)
filter &= Builders<PumpAlarmState>.Filter.Eq(x => x.AlarmType, alarmType);
if (!string.IsNullOrWhiteSpace(alarmCodeMdc))
filter &= Builders<PumpAlarmState>.Filter.Eq(x => x.AlarmCodeMdc, alarmCodeMdc);
return await Collection.Find(filter).FirstOrDefaultAsync();
}
/// <summary>
/// Inserts or updates an active <see cref="PumpAlarmState"/> document, reusing the identifier of an
/// existing record that already matches the same <see cref="PumpAlarmState.DeviceId"/>, <see cref="PumpAlarmState.AlarmType"/>
/// and <see cref="PumpAlarmState.AlarmCodeMdc"/> combination, or generating a new <see cref="ObjectId"/> when
/// <paramref name="state"/> does not yet carry one.
/// </summary>
/// <param name="state">The <see cref="PumpAlarmState"/> to persist; its <see cref="PumpAlarmState.Id"/> is
/// populated from the matching document when one is found, or newly generated when it is currently <see cref="ObjectId.Empty"/>.</param>
/// <!-- aidoc:v1 sig=9119854 body=4bd6c92 -->
public async Task UpsertActiveAsync(PumpAlarmState state)
{
var filter =
Builders<PumpAlarmState>.Filter.Eq(x => x.DeviceId, state.DeviceId) &
Builders<PumpAlarmState>.Filter.Eq(x => x.AlarmType, state.AlarmType) &
Builders<PumpAlarmState>.Filter.Eq(x => x.AlarmCodeMdc, state.AlarmCodeMdc);
// Revisar si ya existe un documento activo con esa combinación
var existing = await Collection.Find(filter).FirstOrDefaultAsync();
if (existing != null)
state.Id = existing.Id;
else
if (state.Id == ObjectId.Empty)
state.Id = ObjectId.GenerateNewId();
await Collection.ReplaceOneAsync(
filter,
state,
new ReplaceOptions { IsUpsert = true });
}
/// <summary>
/// Removes pump alarm state records from the collection that match the specified device identifier, optionally narrowed by alarm type and/or alarm code MDC.
/// </summary>
/// <param name="deviceId">The identifier of the device whose alarm state records should be removed. Used as a mandatory filter criterion.</param>
/// <param name="alarmType">The optional alarm type to further restrict which records are deleted. When <see langword="null"/>, records of any alarm type for the device are removed.</param>
/// <param name="alarmCodeMdc">The optional alarm code MDC used to further narrow the deletion. Blank or whitespace values are ignored.</param>
/// <!-- aidoc:v1 sig=13aeac3 body=e8846f6 -->
public async Task RemoveAsync(string? deviceId, PumpEnum.AlarmType? alarmType, string? alarmCodeMdc = null)
{
var filter = Builders<PumpAlarmState>.Filter.Eq(x => x.DeviceId, deviceId);
if (alarmType.HasValue)
filter &= Builders<PumpAlarmState>.Filter.Eq(x => x.AlarmType, alarmType);
if (!string.IsNullOrWhiteSpace(alarmCodeMdc))
filter &= Builders<PumpAlarmState>.Filter.Eq(x => x.AlarmCodeMdc, alarmCodeMdc);
await Collection.DeleteManyAsync(filter);
}
/// <summary>
/// Asynchronously deletes all records associated with the specified patient identifier by removing every document whose <c>PatientId</c> matches the supplied value.
/// </summary>
/// <param name="patientId">The unique identifier of the patient whose associated records should be removed.</param>
/// <!-- aidoc:v1 sig=4776e51 body=69c2fe9 -->
public async Task DeleteByPatientId(ObjectId patientId)
{
await Collection.DeleteManyAsync(p => p.PatientId == patientId);
}
/// <summary>
/// Asynchronously retrieves all pump alarm states associated with the specified device identifier.
/// </summary>
/// <param name="deviceId">The unique identifier of the device whose pump alarm states are being queried.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains an <see cref="IEnumerable{PumpAlarmState}"/> with the pump alarm states matching the provided device identifier.</returns>
/// <!-- aidoc:v1 sig=a3f8899 body=0854c79 -->
public async Task<IEnumerable<PumpAlarmState>> FindAllActiveByDeviceAsync(string deviceId)
{
return await Collection.Find(x => x.DeviceId == deviceId).ToListAsync();
}
/// <summary>
/// Asynchronously updates all <see cref="PumpAlarmState"/> documents that match the specified <paramref name="oldId"/> on the given <paramref name="fieldName"/>, replacing the value with <paramref name="newId"/>. Used to bulk rewire <see cref="MongoDB.Bson.ObjectId"/> references stored on a dynamic field.
/// </summary>
/// <param name="fieldName">Name of the document field to filter and update.</param>
/// <param name="newId">The new <see cref="MongoDB.Bson.ObjectId"/> value to assign to the field.</param>
/// <param name="oldId">The existing <see cref="MongoDB.Bson.ObjectId"/> value used to locate matching documents.</param>
/// <returns>The number of documents that were modified by the update operation.</returns>
/// <!-- aidoc:v1 sig=885ce8c body=b35cab3 -->
public async Task<long> UpdateManyObjectIdByFieldNameAsync(string fieldName, ObjectId newId, ObjectId oldId)
{
var filter = Builders<PumpAlarmState>.Filter.Eq(fieldName, oldId);
var update = Builders<PumpAlarmState>.Update.Set(fieldName, newId);
var result = await Collection.UpdateManyAsync(filter, update);
return result.ModifiedCount;
}
}