=== Summary: 675 files | 7 generated | 484 fresh | 4605 untracked | 4268 adopted | 355 marked | 466 validated-ok | 2+0 stale (sig+body) | 0 skipped | 0 failed | elapsed 11:08:11.442 (40091.44s) ===

This commit is contained in:
julian
2026-06-28 02:50:05 -07:00
parent a19fb90902
commit 586f02a2ca
654 changed files with 5260 additions and 0 deletions
@@ -17,6 +17,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repositorio para gestionar las operaciones de la entidad Admission en MongoDB. Proporciona métodos para insertar, actualizar, eliminar y buscar admisiones, así como para manejar opciones de listas maestras relacionadas con las admisiones.
/// Utiliza Serilog para el registro de errores y eventos importantes durante las operaciones de la base de datos.
/// </summary>
/// <!-- aidoc:v1 sig=661ecfc -->
public class AdmissionRepository : MongoRepository<Admission>, IAdmissionRepository
{
@@ -41,6 +42,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// Esto permite que el repositorio se conecte a la colección correcta para realizar las operaciones de base de datos relacionadas con las admisiones.
/// </summary>
/// <returns>El nombre de la colección de admisiones en MongoDB.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=c763693 -->
public override string GetCollectionName()
{
return _apiSettings.Admissions;
@@ -51,6 +53,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="admission">La admisión a insertar en la base de datos.</param>
/// <returns>Una tarea que representa la operación asincrónica.</returns>
/// <!-- aidoc:v1 sig=2d2f0a6 body=e87ab8c -->
public override async Task InsertOneAsync(Admission admission)
{
try
@@ -70,6 +73,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="id">El identificador único (ObjectId) de la admisión a eliminar.</param>
/// <returns>Una tarea que representa la operación asincrónica.</returns>
/// <!-- aidoc:v1 sig=3de1ad6 body=27ebee4 -->
public async Task Delete(ObjectId id)
{
try
@@ -89,6 +93,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="admission">La admisión con los datos actualizados.</param>
/// <returns>Una tarea que representa la operación asincrónica.</returns>
/// <!-- aidoc:v1 sig=b1dc4bf body=31005c0 -->
public async Task Update(Admission admission)
{
try
@@ -109,6 +114,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// <param name="id">El identificador único (ObjectId) de la admisión a actualizar.</param>
/// <param name="newLocation">El nuevo identificador de la ubicación (PointOfCareId) de la admisión.</param>
/// <returns>Una tarea que representa la operación asincrónica.</returns>
/// <!-- aidoc:v1 sig=8e1f6ee body=e466f15 -->
public async Task UpdateLocation(ObjectId id, ObjectId newLocation)
{
var filterBuilder = Builders<Admission>.Filter;
@@ -126,6 +132,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// <param name="id">El identificador único (ObjectId) de la admisión a actualizar.</param>
/// <param name="patient">La instancia de Person con los nuevos datos personales.</param>
/// <returns>Una tarea que representa la operación asincrónica.</returns>
/// <!-- aidoc:v1 sig=424027b body=3e081ee -->
public async Task UpdatePatient(ObjectId id, Person patient)
{
var filterBuilder = Builders<Admission>.Filter;
@@ -142,6 +149,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// Si ocurre una excepción durante el proceso, se registra un error con Serilog y se devuelve una lista vacía.
/// </summary>
/// <returns>Una lista de todas las admisiones almacenadas en la base de datos.</returns>
/// <!-- aidoc:v1 sig=c8ce0f4 body=52c24c8 -->
public async Task<IEnumerable<Admission>> FindAll()
{
try
@@ -163,6 +171,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// <param name="patientNumber">El número de paciente (NHC) a buscar.</param>
/// <param name="unitId">El identificador de unidad (ObjectId) que debe ser distinto al de la admisión encontrada.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve la admisión encontrada o null si no se encuentra ninguna.</returns>
/// <!-- aidoc:v1 sig=19a02a2 body=32461f1 -->
public async Task<Admission?> SearchByPatientNumberAndDistinctUnit(string patientNumber, ObjectId unitId)
{
if (string.IsNullOrWhiteSpace(patientNumber)) return null;
@@ -182,6 +191,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="id">El identificador único (ObjectId) de la admisión a buscar.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve la admisión encontrada o null si no se encuentra ninguna.</returns>
/// <!-- aidoc:v1 sig=0698ddf body=138b21a -->
public async Task<Admission?> FindById(ObjectId id)
{
try
@@ -203,6 +213,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="nhc">El número de paciente (NHC) a buscar.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve la admisión encontrada o null si no se encuentra ninguna.</returns>
/// <!-- aidoc:v1 sig=cd32c8c body=a17d4c4 -->
public async Task<Admission?> FindByNhc(string nhc)
{
try
@@ -225,6 +236,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="location">La ubicación del paciente (PatientLocation) a buscar.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve una lista de admisiones que coinciden con la ubicación especificada.</returns>
/// <!-- aidoc:v1 sig=326e4a1 body=c3de436 -->
public async Task<List<Admission>> FindByLocation(PatientLocation location)
{
try
@@ -249,6 +261,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="origin">El nombre del origen de la admisión a buscar.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve una lista de admisiones que coinciden con el origen especificado.</returns>
/// <!-- aidoc:v1 sig=eded8f2 body=1837f4c -->
public async Task<IEnumerable<Admission>?> FindByOrigin(string origin)
{
try
@@ -273,6 +286,8 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="origin">La admisión a insertar.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve la admisión insertada o null si ocurre un error.</returns>
/// <!-- aidoc-review:v1 severity=high kind=mentions_removed_behavior
/// "The summary states the method sets AdmissionDate to the current UTC date/time before insertion, but the code never assigns or modifies AdmissionDate." -->
public async Task<Admission?> InsertOneAsyncAndReturn(Admission origin)
{
try
@@ -293,6 +308,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="unitId">El identificador de la unidad a buscar.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve una lista de admisiones que coinciden con los criterios especificados.</returns>
/// <!-- aidoc:v1 sig=a0f7f96 body=976a399 -->
public async Task<List<Admission>> GetAdmissionByUnitIdWithOutPoC(ObjectId unitId)
{
try
@@ -314,6 +330,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="unitId">El identificador de la unidad a buscar.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve el número de admisiones que coinciden con el unitId especificado.</returns>
/// <!-- aidoc:v1 sig=baa8175 body=0635d14 -->
public async Task<long> CountByUnitId(ObjectId unitId)
{
try
@@ -335,6 +352,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="pocId">El identificador del punto de atención a buscar.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve una lista de admisiones que coinciden con el PointOfCareId especificado.</returns>
/// <!-- aidoc:v1 sig=ff96e2c body=6fe7177 -->
public async Task<List<Admission>> FindByPointOfCareId(ObjectId pocId)
{
try
@@ -356,6 +374,8 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="unitIds">La lista de identificadores de unidad a buscar.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve una lista de admisiones que coinciden con los unitIds especificados.</returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_summary
/// "The summary states that the method 'utiliza el método FindAsync para obtenerlas', but the code actually uses Collection.Find(filterUnit).ToListAsync(), not FindAsync." -->
public async Task<List<Admission>> FindByUnitIds(List<ObjectId> unitIds)
{
var filterUnit = Builders<Admission>.Filter.In("unitId", unitIds);
@@ -369,6 +389,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// <param name="opt">La opción de actualización de la lista maestra.</param>
/// <param name="typeName">El nombre del tipo de lista maestra.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve una lista de admisiones actualizadas.</returns>
/// <!-- aidoc:v1 sig=eb0fbec body=436eb94 -->
public async Task<IEnumerable<Admission>> UpdateMasterListOption(List<ObjectId> unitIds,
UpdateOptionMasterListDto opt, string typeName)
{
@@ -459,6 +480,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// <param name="opt">La opción de actualización de la lista maestra.</param>
/// <param name="typeName">El nombre del tipo de lista maestra.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve una lista de admisiones actualizadas.</returns>
/// <!-- aidoc:v1 sig=b26eefb body=eea63d3 -->
public async Task<IEnumerable<Admission>> DeleteMasterListOption(List<ObjectId> unitIds, OptionList opt,
string typeName)
{
@@ -552,6 +574,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="unitId">El identificador de la unidad cuyas admisiones se eliminarán.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve un valor booleano que indica si la eliminación fue exitosa.</returns>
/// <!-- aidoc:v1 sig=9070532 body=ce4ae70 -->
public async Task<bool> DeleteAdmissionsByUnitId(ObjectId unitId)
{
try
@@ -571,6 +594,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// Crea índices en la colección de admisiones para mejorar el rendimiento de las consultas. En este caso, se crea un índice único en el campo "nhc" (número de paciente) que solo se aplica a los documentos que tienen un valor para "nhc".
/// </summary>
/// <returns>Una tarea que representa la operación asincrónica.</returns>
/// <!-- aidoc:v1 sig=4955da2 body=5d1f175 -->
public override async Task CreateIndexes()
{
var optionsUq = new CreateIndexOptions<Admission>
@@ -593,6 +617,7 @@ public class AdmissionRepository : MongoRepository<Admission>, IAdmissionReposit
/// </summary>
/// <param name="diagnosis">El nombre del diagnóstico que se utilizará para buscar admisiones.</param>
/// <returns>Una tarea que representa la operación asincrónica y devuelve una colección de admisiones que coinciden con el diagnóstico especificado.</returns>
/// <!-- aidoc:v1 sig=50438e0 body=f744392 -->
public async Task<IEnumerable<Admission>?> FindByDiagnosis(string diagnosis)
{
try
@@ -15,6 +15,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repository for managing patient observation alarms in MongoDB. Provides methods to retrieve aggregated patient observations based on specified fields and expiration status.
/// Implements the IAlarmRepository interface and extends the MongoRepository base class for common MongoDB operations.
/// </summary>
/// <!-- aidoc:v1 sig=38c745c -->
public class AlarmRepository : MongoRepository<PatientObservationAlarm>, IAlarmRepository
{
/// <summary>
@@ -35,6 +36,8 @@ public class AlarmRepository : MongoRepository<PatientObservationAlarm>, IAlarmR
/// <param name="database">The MongoDB database instance.</param>
/// <param name="logger">The logger instance for logging errors and information.</param>
/// <exception cref="ArgumentNullException">Thrown when any of the input parameters are null.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "Documents ArgumentNullException as thrown 'when any of the input parameters are null', but the code only null-checks apiSettings; database and logger are not validated." -->
public AlarmRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database, ILogger<AlarmRepository> logger)
: base(database)
{
@@ -51,6 +54,7 @@ public class AlarmRepository : MongoRepository<PatientObservationAlarm>, IAlarmR
/// <param name="patientId">The unique identifier of the patient.</param>
/// <param name="filterObservations">A list of fields to filter the observations. If null, all observations for the patient are retrieved.</param>
/// <returns>A list of patient observation alarms matching the filter criteria.</returns>
/// <!-- aidoc:v1 sig=43640c3 body=c02d57d -->
public async Task<List<PatientObservationAlarm>> AggregatedPatientLastObservationsByField(ObjectId patientId,
List<Field>? filterObservations = null)
{
@@ -118,6 +122,7 @@ public class AlarmRepository : MongoRepository<PatientObservationAlarm>, IAlarmR
/// <param name="filterObservations">A list of fields to filter the observations. If null, all observations for the patient are retrieved.</param>
/// <param name="configAlarm">A list of configuration settings for the observations, including expiration times.</param>
/// <returns>A list of patient observation alarms matching the filter criteria and expiration settings.</returns>
/// <!-- aidoc:v1 sig=4c42a94 body=1caea2e -->
public async Task<List<PatientObservationAlarm>> AggregatedPatientNotExpiredObservationsByField(
ObjectId patientId,
List<Field>? filterObservations,
@@ -193,6 +198,7 @@ public class AlarmRepository : MongoRepository<PatientObservationAlarm>, IAlarmR
/// If the collection name is not specified in the API settings, it defaults to "patients_alarms".
/// </summary>
/// <returns>The name of the MongoDB collection for patient observation alarms.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=e2ee5dc -->
public override string GetCollectionName()
{
return _apiSettings.PatientsAlarms ?? "patients_alarms";
@@ -202,6 +208,7 @@ public class AlarmRepository : MongoRepository<PatientObservationAlarm>, IAlarmR
/// Creates indexes for the patient observation alarms collection in MongoDB to optimize query performance.
/// </summary>
/// <returns>A task that represents the asynchronous operation of creating indexes.</returns>
/// <!-- aidoc:v1 sig=4955da2 body=340db89 -->
public override async Task CreateIndexes()
{
try
@@ -10,6 +10,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Repository for managing archived patient appointments in MongoDB. This repository provides methods to insert, delete, and manage archived appointments, ensuring efficient storage and retrieval of historical appointment data.
/// </summary>
/// <!-- aidoc:v1 sig=fd51b07 -->
public class AppointmentArchiveRepository : MongoRepository<PatientAppointment>, IAppointmentArchiveRepository
{
/// <summary>
@@ -24,6 +25,8 @@ public class AppointmentArchiveRepository : MongoRepository<PatientAppointment>,
/// <param name="apiSettings">The API settings containing configuration for the archive collection.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <exception cref="ArgumentNullException">Thrown when any of the input parameters are null.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_exception
/// "The exception description states it is 'Thrown when any of the input parameters are null', but only apiSettings is null-checked; database is passed to the base constructor without a null check." -->
public AppointmentArchiveRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
{
if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
@@ -37,6 +40,7 @@ public class AppointmentArchiveRepository : MongoRepository<PatientAppointment>,
/// </summary>
/// <param name="appointment">The patient appointment to be inserted into the archive collection.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=160dca2 body=ec779ee -->
public override async Task InsertOneAsync(PatientAppointment appointment)
{
await Collection.InsertOneAsync(appointment);
@@ -47,6 +51,7 @@ public class AppointmentArchiveRepository : MongoRepository<PatientAppointment>,
/// </summary>
/// <param name="date">The date before which all patient appointments should be deleted.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=63daa66 body=c6d74c3 -->
public async Task DeleteBeforeDate(DateTime date)
{
var filter = Builders<PatientAppointment>.Filter.Lt(pa => pa.CreateTime, date);
@@ -59,6 +64,7 @@ public class AppointmentArchiveRepository : MongoRepository<PatientAppointment>,
/// </summary>
/// <param name="appointment">The collection of patient appointments to be inserted into the archive.</param>
/// <returns>A task representing the asynchronous operation, with the result being the count of inserted documents.</returns>
/// <!-- aidoc:v1 sig=c7c2d89 body=e3ee2bb -->
public async Task<long> InsertBatch(IEnumerable<PatientAppointment> appointment)
{
var writes = new List<WriteModel<PatientAppointment>>();
@@ -74,6 +80,7 @@ public class AppointmentArchiveRepository : MongoRepository<PatientAppointment>,
/// If the collection name is not specified in the settings, it defaults to "archive_patients_appointments".
/// </summary>
/// <returns>The name of the MongoDB collection for archived patient appointments.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=6f721df -->
public override string GetCollectionName()
{
return _apiSettings.ArchivePatientsAppointments ?? "archive_patients_appointments";
@@ -83,6 +90,7 @@ public class AppointmentArchiveRepository : MongoRepository<PatientAppointment>,
/// Creates indexes on the MongoDB collection for archived patient appointments to optimize query performance. This method defines the necessary indexes, such as an index on the "patientid" field, and ensures that they are created in the background without blocking other operations.
/// </summary>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=4955da2 body=1a9cdb6 -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions<PatientAppointment> { Background = true, Unique = false };
@@ -14,6 +14,7 @@ namespace adas_core.Infrastructure.Repositories;
/// This class provides methods to perform CRUD operations and queries related to patient appointments, such as retrieving appointments by patient ID, finding appointments by point of care, and updating or deleting appointments.
/// It utilizes the MongoDB driver for database interactions and is configured using application settings for collection names and other parameters.
/// </summary>
/// <!-- aidoc:v1 sig=2015cdb -->
public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppointmentRepository
{
/// <summary>
@@ -27,6 +28,8 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// <param name="apiSettings">The API settings containing configuration for the repository.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <exception cref="ArgumentNullException">Thrown when any of the input parameters are null.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_exception
/// "Documentation states ArgumentNullException is thrown when 'any of the input parameters are null', but only apiSettings is null-checked in the constructor body; database is passed to the base constructor without an explicit null check." -->
public AppointmentRepository(
IOptions<ApiSettings> apiSettings,
IMongoDatabase database) : base(database)
@@ -41,6 +44,7 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// If the collection name is not specified in the settings, it defaults to "patients_appointments".
/// </summary>
/// <returns>The name of the MongoDB collection for patient appointments.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=d8275f8 -->
public override string GetCollectionName()
{
return _apiSettings.PatientsAppointments ?? "patients_appointments";
@@ -51,6 +55,7 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// </summary>
/// <param name="patientId">The ID of the patient whose appointments are to be retrieved.</param>
/// <returns>A list of patient appointments for the specified patient ID.</returns>
/// <!-- aidoc:v1 sig=c45e6c0 body=7fc6917 -->
public async Task<List<PatientAppointment>> GetByPatient(ObjectId patientId)
{
var filter = Builders<PatientAppointment>.Filter.Eq(ob => ob.PatientId, patientId);
@@ -69,6 +74,7 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// </summary>
/// <param name="poc">The point of care details to filter appointments.</param>
/// <returns>A list of patient appointments that match the specified point of care.</returns>
/// <!-- aidoc:v1 sig=6e05c46 body=b220747 -->
public async Task<List<PatientAppointment>> FindByPoC(PointOfCare poc)
{
var location = new PatientLocation()
@@ -85,6 +91,7 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// </summary>
/// <param name="appointment">The patient appointment to be inserted.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=160dca2 body=b1d1f38 -->
public override async Task InsertOneAsync(PatientAppointment appointment)
{
appointment.CreateTime ??= DateTime.UtcNow;
@@ -97,6 +104,7 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// </summary>
/// <param name="appointment">The patient appointment to be updated.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=6653577 body=7202215 -->
public async Task Update(PatientAppointment appointment)
{
await UpdateOneAsync(appointment.Id, appointment);
@@ -107,6 +115,7 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// </summary>
/// <param name="id">The ID of the patient appointment to be deleted.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=78c6c5d body=673af1f -->
public new async Task DeleteAsync(ObjectId id)
{
var filter = Builders<PatientAppointment>.Filter.Eq(t => t.Id, id); // Replace 'T' with your actual class name.
@@ -118,6 +127,7 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// </summary>
/// <param name="patientId">The ID of the patient whose appointments are to be retrieved.</param>
/// <returns>An asynchronous cursor to iterate through the patient appointments.</returns>
/// <!-- aidoc:v1 sig=737aa7b body=4dc939c -->
public Task<IAsyncCursor<PatientAppointment>> FindByPatientIdAsync(ObjectId patientId)
{
var filter = Builders<PatientAppointment>.Filter.Eq(ob => ob.PatientId, patientId);
@@ -129,6 +139,7 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// </summary>
/// <param name="patientId">The ID of the patient whose appointments are to be deleted.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=4776e51 body=b5830ef -->
public async Task DeleteByPatientId(ObjectId patientId)
{
var filter = Builders<PatientAppointment>.Filter.Eq(po => po.PatientId, patientId);
@@ -141,6 +152,7 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// <param name="patientId">The ID of the patient whose appointment is to be retrieved.</param>
/// <param name="visitNumber">The visit number of the appointment to be retrieved.</param>
/// <returns>The first matching patient appointment if found, or null if no match is found.</returns>
/// <!-- aidoc:v1 sig=713bd29 body=0453b7b -->
public async Task<PatientAppointment?> FindByPatientAndVisitNumber(ObjectId patientId, string visitNumber)
{
var builder = Builders<PatientAppointment>.Filter;
@@ -160,6 +172,7 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// <param name="patientId">The ID of the patient whose appointment is to be retrieved.</param>
/// <param name="appointmentReason">The reason for the appointment to be retrieved.</param>
/// <returns>The first matching patient appointment if found, or null if no match is found.</returns>
/// <!-- aidoc:v1 sig=0d22413 body=622cd38 -->
public async Task<PatientAppointment?> FindByPatientAndReason(ObjectId patientId, string? appointmentReason)
{
var builder = Builders<PatientAppointment>.Filter;
@@ -178,6 +191,8 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// </summary>
/// <param name="location">The location details to filter patient appointments by.</param>
/// <returns>A list of patient appointments that match the specified location.</returns>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_summary
/// "The summary states the location 'includes details such as bed, room, and unit name', but the code only filters by Bed and UnitName; Room is not part of the filter." -->
public async Task<List<PatientAppointment>> FindByLocation(PatientLocation location)
{
var builder = Builders<PatientAppointmentResourceGroup>.Filter;
@@ -200,6 +215,10 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// <param name="id">The new ObjectId to replace the old patient ID.</param>
/// <param name="oldId">The old ObjectId of the patient whose appointments are to be updated.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary states this method constructs a filter and uses UpdateManyAsync, but the code only awaits a call to UpdateManyObjectIdAsync without constructing any filter or calling UpdateManyAsync directly." -->
/// <!-- aidoc-review:v1 severity=high kind=mentions_removed_behavior
/// "Mentions 'UpdateManyAsync method' which is not invoked here; the method delegates to UpdateManyObjectIdAsync instead." -->
public async Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId)
{
await UpdateManyObjectIdAsync(nameId, id, oldId);
@@ -210,6 +229,7 @@ public class AppointmentRepository : MongoRepository<PatientAppointment>, IAppoi
/// The indexes are created in the background and are not unique.
/// </summary>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=4955da2 body=178452d -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions { Background = true, Unique = false };
@@ -14,6 +14,7 @@ namespace adas_core.Infrastructure.Repositories;
/// This class provides methods to perform CRUD operations and queries related to archived patient care plans, such as retrieving care plans by patient ID, inserting new care plans, and creating indexes.
/// It utilizes the MongoDB driver for database interactions and is configured using application settings for collection names and other parameters.
/// </summary>
/// <!-- aidoc:v1 sig=20f996a -->
public class ArchivePatientCarePlanRepository : MongoRepository<PatientCarePlan>, IArchivePatientCarePlanRepository
{
#region Properties
@@ -37,6 +38,7 @@ public class ArchivePatientCarePlanRepository : MongoRepository<PatientCarePlan>
/// <param name="apiSettings">The API settings containing configuration for the repository.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <param name="logger">The logger for logging information, warnings, and errors.</param>
/// <!-- aidoc:v1 sig=ac3a86d body=8a9d2fd -->
public ArchivePatientCarePlanRepository(
IOptions<ApiSettings> apiSettings,
IMongoDatabase database,
@@ -51,6 +53,7 @@ public class ArchivePatientCarePlanRepository : MongoRepository<PatientCarePlan>
/// This method ensures that the necessary indexes are created to optimize query performance, particularly for queries based on patient ID. The indexes are created in the background to avoid blocking operations on the database.
/// </summary>
/// <returns></returns>
/// <!-- aidoc:v1 sig=4955da2 body=747164e -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions<PatientCarePlan> { Background = true, Unique = false };
@@ -73,6 +76,7 @@ public class ArchivePatientCarePlanRepository : MongoRepository<PatientCarePlan>
/// </summary>
/// <param name="patient">The patient care plan to be inserted.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=06563e4 body=65f486e -->
public override async Task InsertOneAsync(PatientCarePlan patient)
{
try
@@ -93,6 +97,7 @@ public class ArchivePatientCarePlanRepository : MongoRepository<PatientCarePlan>
/// </summary>
/// <param name="patient">The list of patient care plans to be inserted.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=67f7f21 body=d6d5f8a -->
public override async Task InsertManyAsync(List<PatientCarePlan> patient)
{
try
@@ -116,6 +121,7 @@ public class ArchivePatientCarePlanRepository : MongoRepository<PatientCarePlan>
/// This method is used by the base repository class to determine which collection to interact with for CRUD operations.
/// </summary>
/// <returns></returns>
/// <!-- aidoc:v1 sig=94e22ff body=a3f1bbe -->
public override string GetCollectionName()
{
return _apiSettings.ArchivePatientProcedure ?? "archive_patients_care_plan";
@@ -127,6 +133,7 @@ public class ArchivePatientCarePlanRepository : MongoRepository<PatientCarePlan>
/// </summary>
/// <param name="patientId">The ID of the patient whose care plans are to be retrieved.</param>
/// <returns>A task representing the asynchronous operation, containing a list of <see cref="PatientCarePlan"/> objects.</returns>
/// <!-- aidoc:v1 sig=33d98b1 body=fae3443 -->
public async Task<List<PatientCarePlan>?> FindByPatientId(ObjectId patientId)
{
var result = await Collection.FindAsync(Builders<PatientCarePlan>.Filter.Eq(p => p.PatientId, patientId));
@@ -138,6 +145,7 @@ public class ArchivePatientCarePlanRepository : MongoRepository<PatientCarePlan>
/// </summary>
/// <param name="patientId">The ID of the patient whose care plans are to be retrieved, provided as a string.</param>
/// <returns>A task representing the asynchronous operation, containing a list of <see cref="PatientCarePlan"/> objects.</returns>
/// <!-- aidoc:v1 sig=9198094 body=7897dce -->
public async Task<List<PatientCarePlan>?> FindByPatientId(string patientId)
{
var isParsed = ObjectId.TryParse(patientId, out var patientIdParsed);
@@ -151,6 +159,7 @@ public class ArchivePatientCarePlanRepository : MongoRepository<PatientCarePlan>
/// </summary>
/// <param name="patientNumber">The number of the patient whose care plans are to be retrieved.</param>
/// <returns>A task representing the asynchronous operation, containing a list of <see cref="PatientCarePlan"/> objects.</returns>
/// <!-- aidoc:v1 sig=3c65a30 body=41e7132 -->
public async Task<List<PatientCarePlan>?> FindByPatientNumber(string patientNumber)
{
var result = await Collection.FindAsync(Builders<PatientCarePlan>.Filter.Eq(p => p.PatientNumber, patientNumber));
@@ -161,6 +170,7 @@ public class ArchivePatientCarePlanRepository : MongoRepository<PatientCarePlan>
/// Finds all patient care plans in the MongoDB collection. This method retrieves all documents from the collection and returns them as a list of <see cref="PatientCarePlan"/> objects.
/// </summary>
/// <returns>A task representing the asynchronous operation, containing a list of <see cref="PatientCarePlan"/> objects.</returns>
/// <!-- aidoc:v1 sig=6a558a7 body=faea989 -->
public async Task<List<PatientCarePlan>> FindAll()
{
var result = await Collection.Find(Builders<PatientCarePlan>.Filter.Empty).ToListAsync();
@@ -176,6 +186,7 @@ public class ArchivePatientCarePlanRepository : MongoRepository<PatientCarePlan>
/// <param name="oldPatientPatientId">The ID of the patient whose care plans are to be retrieved, provided as a string.</param>
/// <param name="oldPatientPatientNumber">The number of the patient whose care plans are to be retrieved.</param>
/// <returns>A task representing the asynchronous operation, containing a list of <see cref="PatientCarePlan"/> objects.</returns>
/// <!-- aidoc:v1 sig=1d58fb5 body=6e9839e -->
public async Task<List<PatientCarePlan>?> FindByIds(ObjectId oldPatientId, string? oldPatientPatientId,
string? oldPatientPatientNumber)
{
@@ -15,6 +15,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <param name="apiSettings">The API settings containing configuration for the repository.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <param name="logger">The logger for logging information, warnings, and errors.</param>
/// <!-- aidoc:v1 sig=01b7bc7 -->
public class AuthorityRepository(
IOptions<ApiSettings> apiSettings,
IMongoDatabase database,
@@ -29,6 +30,7 @@ public class AuthorityRepository(
/// </summary>
/// <param name="roleName">The name of the role to be assigned to the new authority.</param>
/// <param name="userId">The ID of the user for whom the new authority is being created.</param>
/// <!-- aidoc:v1 sig=29e2cb9 body=ec4fdec -->
public void CreateNewAuthority(string roleName, ObjectId userId)
{
var newAuthorization = new Authorization
@@ -48,6 +50,7 @@ public class AuthorityRepository(
/// </summary>
/// <param name="userId">The ID of the user whose authorities are being retrieved.</param>
/// <returns>A list of authorities associated with the specified user ID.</returns>
/// <!-- aidoc:v1 sig=15ea92f body=00b4901 -->
public async Task<List<Authorization>> GetUserAuthorities(ObjectId userId)
{
var filter = Builders<Authorization>.Filter.Eq(p => p.UserId, userId);
@@ -60,6 +63,7 @@ public class AuthorityRepository(
/// Retrieves a list of all authorities in the system. This method queries the database for all authority records and returns them as a list. It also logs the retrieval of all authorities for debugging purposes.
/// </summary>
/// <returns>A list of all authorities in the system.</returns>
/// <!-- aidoc:v1 sig=e98ee21 body=736e0af -->
public async Task<List<Authorization>> GetAllAuthorities()
{
var result = await Collection.FindAsync(Builders<Authorization>.Filter.Empty);
@@ -73,6 +77,7 @@ public class AuthorityRepository(
/// </summary>
/// <param name="unitId">The ID of the unit whose authorities are being retrieved.</param>
/// <returns>A list of authorities associated with the specified unit ID.</returns>
/// <!-- aidoc:v1 sig=37cf403 body=a1ee959 -->
public async Task<List<Authorization>> GetByUnitId(ObjectId unitId)
{
var filter = Builders<Authorization>.Filter.Eq(a => a.UnitId, unitId.ToString());
@@ -90,6 +95,7 @@ public class AuthorityRepository(
/// </summary>
/// <param name="userId">The ID of the user whose authorities are being deleted.</param>
/// <returns>A boolean value indicating whether the deletion was successful.</returns>
/// <!-- aidoc:v1 sig=731646b body=b62575f -->
public async Task<bool> DeleteAllAuthoritiesByUser(ObjectId userId)
{
try
@@ -113,6 +119,7 @@ public class AuthorityRepository(
/// </summary>
/// <param name="unitId">The ID of the unit whose authorities are being deleted.</param>
/// <returns>A boolean value indicating whether the deletion was successful.</returns>
/// <!-- aidoc:v1 sig=3e0e6b6 body=4adf653 -->
public async Task<bool> DeleteAllAuthoritiesByUnit(ObjectId unitId)
{
try
@@ -134,6 +141,7 @@ public class AuthorityRepository(
/// </summary>
/// <param name="displayId">The ID of the display whose authorities are being deleted.</param>
/// <returns>A boolean value indicating whether the deletion was successful.</returns>
/// <!-- aidoc:v1 sig=a4dbbd6 body=3f3c2b8 -->
public async Task<bool> DeleteAllAuthoritiesByDisplay(ObjectId displayId)
{
try
@@ -153,6 +161,7 @@ public class AuthorityRepository(
/// Retrieves the name of the collection used for storing authorities in the database. This method returns the collection name as specified in the API settings configuration.
/// </summary>
/// <returns></returns>
/// <!-- aidoc:v1 sig=94e22ff body=f98b290 -->
public override string GetCollectionName()
{
return _apiSettings.Authorizations;
@@ -164,6 +173,8 @@ public class AuthorityRepository(
/// </summary>
/// <param name="authId">The unique identifier of the authority to be retrieved.</param>
/// <returns>The authority that matches the provided ID, or null if no matching authority is found.</returns>
/// <!-- aidoc-review:v1 severity=high kind=mentions_removed_behavior
/// "Summary claims the method logs the retrieval for debugging purposes, but no logging code is present in the method body." -->
public async Task<Authorization> GetById(ObjectId authId)
{
var filter = Builders<Authorization>.Filter.Eq(p => p.Id, authId);
@@ -176,6 +187,7 @@ public class AuthorityRepository(
/// This method is typically called during the initial setup of the application to ensure that essential data is present in the database.
/// </summary>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=ccdefcf body=d957dc7 -->
public sealed override async Task InsertInitialLoad()
{
var user = Db.GetCollection<User>(apiSettings.Value.Users);
@@ -16,6 +16,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repository for managing camera entities in the MongoDB database. This repository provides methods to create, retrieve, update, and search for cameras based on various criteria.
/// It also includes error handling and logging for debugging purposes.
/// </summary>
/// <!-- aidoc:v1 sig=003e7c1 -->
public class CameraRepository : MongoRepository<Camera>, ICameraRepository
{
private readonly ApiSettings _apiSettings;
@@ -26,6 +27,7 @@ public class CameraRepository : MongoRepository<Camera>, ICameraRepository
/// </summary>
/// <param name="database">The MongoDB database instance.</param>
/// <param name="apiSettings">The API settings containing configuration for the repository.</param>
/// <!-- aidoc:v1 sig=e4f283c body=12fddac -->
public CameraRepository(IMongoDatabase database, IOptions<ApiSettings> apiSettings) : base(database)
{
_apiSettings = apiSettings.Value;
@@ -35,6 +37,7 @@ public class CameraRepository : MongoRepository<Camera>, ICameraRepository
/// Gets the name of the MongoDB collection that this repository interacts with. In this case, it returns the collection name for cameras as specified in the API settings.
/// </summary>
/// <returns>The name of the MongoDB collection for cameras.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=05f9f4e -->
public override string GetCollectionName()
{
return _apiSettings.Cameras;
@@ -46,6 +49,7 @@ public class CameraRepository : MongoRepository<Camera>, ICameraRepository
/// </summary>
/// <param name="cameraId">The unique identifier of the camera to retrieve.</param>
/// <returns>The Camera object if found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=6eb1bff body=8816446 -->
public async Task<Camera?> GetById(ObjectId cameraId)
{
try
@@ -66,6 +70,7 @@ public class CameraRepository : MongoRepository<Camera>, ICameraRepository
/// </summary>
/// <param name="name">The name of the camera to retrieve.</param>
/// <returns>The Camera object if found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=42cd675 body=e41e30c -->
public async Task<Camera?> GetByName(string name)
{
var filterBuilder = Builders<Camera>.Filter;
@@ -81,6 +86,7 @@ public class CameraRepository : MongoRepository<Camera>, ICameraRepository
/// </summary>
/// <param name="configurationRelayList">The list of camera IDs to retrieve.</param>
/// <returns>A list of Camera objects that match the provided IDs.</returns>
/// <!-- aidoc:v1 sig=63176e6 body=14b9319 -->
public List<Camera> GetCameraInList(List<ObjectId> configurationRelayList)
{
var filterBuilder = Builders<Camera>.Filter;
@@ -98,6 +104,12 @@ public class CameraRepository : MongoRepository<Camera>, ICameraRepository
/// <param name="filter">The pagination filter containing page number, page size, and any additional filtering criteria.</param>
/// <returns>A paginated list of Camera objects.</returns>
/// <exception cref="BadRequestException">Thrown when the provided filter is invalid or contains invalid data.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "Method returns IFindFluent<Camera, Camera>, not a paginated list of Camera objects." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Summary claims it 'retrieves a paginated list of camera entities' but the method returns an IFindFluent query builder, not a list." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "BadRequestException is thrown only when the text filter exceeds 100 characters; doc describes it generically as 'invalid filter or invalid data'." -->
public IFindFluent<Camera, Camera> GetPaginatedCameras(PaginationFilter filter)
{
var filterBuilder = Builders<Camera>.Filter;
@@ -133,6 +145,7 @@ public class CameraRepository : MongoRepository<Camera>, ICameraRepository
/// </summary>
/// <param name="camera">The Camera object to insert into the database.</param>
/// <returns>The inserted Camera object if successful; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=4c3fa66 body=c723ea9 -->
public async Task<Camera?> InsertOneCamera(Camera camera)
{
try
@@ -155,6 +168,7 @@ public class CameraRepository : MongoRepository<Camera>, ICameraRepository
/// <param name="objectId">The unique identifier of the camera to update.</param>
/// <param name="camera">The Camera object containing the updated information.</param>
/// <returns>The updated Camera object if successful; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=5dea533 body=003b000 -->
public async Task<Camera?> UpdateCameraAsync(ObjectId objectId, Camera camera)
{
var filter = Builders<Camera>.Filter.Eq("_id", objectId);
@@ -178,6 +192,7 @@ public class CameraRepository : MongoRepository<Camera>, ICameraRepository
/// <param name="textToSearch">The text string to search for in the camera names.</param>
/// <returns>A list of Camera objects whose names match the search criteria.</returns>
/// <exception cref="BadRequestException">Thrown when the search text is too long.</exception>
/// <!-- aidoc:v1 sig=a584e66 body=efc6951 -->
public async Task<List<Camera>> GetSearchByNameCameras(string textToSearch)
{
if (string.IsNullOrWhiteSpace(textToSearch))
@@ -202,6 +217,7 @@ public class CameraRepository : MongoRepository<Camera>, ICameraRepository
/// <param name="filters">A list of filter definitions to apply to the query.</param>
/// <param name="sort">A sort definition to apply to the query results.</param>
/// <returns>An IFindFluent object for further query customization or execution.</returns>
/// <!-- aidoc:v1 sig=7aa3c5c body=e772829 -->
private IFindFluent<Camera, Camera> CreateFindFluent(List<FilterDefinition<Camera>> filters, SortDefinition<Camera> sort)
{
var combinedFilter = filters.Any()
@@ -15,6 +15,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Repositorio para manejar las operaciones CRUD de ConfigObservation en MongoDB.
/// </summary>
/// <!-- aidoc:v1 sig=a788dff -->
public class ConfigObservationRepository : MongoRepository<ConfigObservation>, IConfigObservationRepository
{
private readonly ApiSettings _apiSettings;
@@ -26,6 +27,7 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// <param name="apiSettings">Configuración de la API.</param>
/// <param name="database">Instancia de la base de datos MongoDB.</param>
/// <param name="masterListServiceFactory">Fábrica de servicios de lista maestra.</param>
/// <!-- aidoc:v1 sig=da6c2d3 body=58ec731 -->
public ConfigObservationRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database,
IMasterListServiceFactory masterListServiceFactory) : base(database)
{
@@ -37,6 +39,7 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// Obtiene el nombre de la colección de MongoDB para ConfigObservation, utilizando la configuración proporcionada o un valor predeterminado.
/// </summary>
/// <returns>El nombre de la colección de MongoDB para ConfigObservation.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=101bc42 -->
public override string GetCollectionName()
{
return _apiSettings.ConfigObservations ?? "config_observations";
@@ -47,6 +50,7 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// </summary>
/// <param name="id">El ID del ConfigObservation a buscar.</param>
/// <returns>El ConfigObservation encontrado, o null si no se encuentra.</returns>
/// <!-- aidoc:v1 sig=9e9dbe7 body=eb0c8ec -->
public async Task<ConfigObservation?> FindById(ObjectId id)
{
var result = await Collection.FindAsync(Builders<ConfigObservation>.Filter.Eq(x => x.Id, id));
@@ -58,6 +62,8 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// </summary>
/// <param name="configObservation">El ConfigObservation con los datos actualizados.</param>
/// <returns>El ConfigObservation actualizado, o null si no se encuentra.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "The documentation states it returns null if the document is not found, but the method body unconditionally returns the input configObservation parameter and never returns null." -->
public async Task<ConfigObservation?> Update(ConfigObservation configObservation)
{
await UpdateOneAsync(configObservation.Id, configObservation);
@@ -69,6 +75,7 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
/// <!-- aidoc:v1 sig=0493ac3 body=040c92d -->
public async Task<ConfigObservation?> Delete(ObjectId id)
{
return await DeleteAsync(id);
@@ -78,6 +85,7 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// Busca todos los IDs de ConfigObservation en la base de datos MongoDB.
/// </summary>
/// <returns>Una lista de todos los IDs de ConfigObservation.</returns>
/// <!-- aidoc:v1 sig=9552257 body=197e2a4 -->
public async Task<List<ObjectId>> FindAllIds()
{
var allCollection = await Collection.FindAsync(_ => true);
@@ -89,6 +97,7 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// Busca todos los ConfigObservation en la base de datos MongoDB.
/// </summary>
/// <returns>Una colección de todos los ConfigObservation.</returns>
/// <!-- aidoc:v1 sig=9ac53aa body=abac63b -->
public async Task<ICollection<ConfigObservation>> FindAll()
{
var result = await Collection.FindAsync(_ => true);
@@ -100,6 +109,8 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// </summary>
/// <param name="id">El ID del ConfigObservation para filtrar los nombres (opcional).</param>
/// <returns>Una lista de nombres de ConfigObservation.</returns>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_param_role
/// "The 'id' parameter is documented as used to filter names, but the code never references it; the MongoDB filter is '_ => true' (all documents)." -->
public async Task<List<string>> GetConfigNames(string id)
{
var allConfigs = await Collection.Find(_ => true).ToListAsync();
@@ -117,6 +128,8 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// Busca todos los nombres de ConfigObservation en la base de datos MongoDB, eliminando duplicados y espacios en blanco.
/// </summary>
/// <returns></returns>
/// <!-- aidoc-review:v1 severity=medium kind=missing_returns
/// "The <returns> tag is empty and does not describe that the method returns a list of distinct, case-insensitive, trimmed configuration names." -->
public async Task<List<string>> GetConfigNames()
{
var allConfigs = await Collection.Find(_ => true).ToListAsync();
@@ -134,6 +147,7 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// Cuenta el número total de ConfigObservation en la base de datos MongoDB.
/// </summary>
/// <returns>El número total de ConfigObservation.</returns>
/// <!-- aidoc:v1 sig=acac1a2 body=4039511 -->
public async Task<long> Count()
{
var filter = Builders<ConfigObservation>.Filter.Empty;
@@ -147,6 +161,7 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// <param name="filter">El filtro de paginación y búsqueda.</param>
/// <returns>Una colección de ConfigObservation que cumple con los criterios de búsqueda y paginación.</returns>
/// <exception cref="BadRequestException">Se lanza cuando el texto de búsqueda es demasiado largo.</exception>
/// <!-- aidoc:v1 sig=bfdfd9c body=7c0d92a -->
public async Task<ICollection<ConfigObservation>> GetPaginatedItems(PaginationFilter filter)
{
var builder = Builders<ConfigObservation>.Filter;
@@ -196,6 +211,7 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// <param name="name">El nombre del ConfigObservation a buscar.</param>
/// <returns>El ConfigObservation que coincide con el nombre proporcionado, o null si no se encuentra.</returns>
/// <exception cref="BadRequestException">Se lanza cuando el nombre es nulo, vacío o demasiado largo.</exception>
/// <!-- aidoc:v1 sig=dd521a7 body=acfad20 -->
public async Task<ConfigObservation?> FindByName(string name)
{
if (string.IsNullOrWhiteSpace(name))
@@ -222,6 +238,8 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// <param name="codingSystem">El sistema de codificación del ConfigObservation a buscar.</param>
/// <param name="code">El código del ConfigObservation a buscar.</param>
/// <returns>El ConfigObservation que coincide con el sistema de codificación y código proporcionados, o null si no se encuentra.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary states the search is case-insensitive ('búsqueda insensible a mayúsculas y minúsculas'), but the code uses Builders.Filter.Eq which is a case-sensitive equality match." -->
public async Task<ConfigObservation?> GetByCodeSysAndCode(string? codingSystem, string? code)
{
var builder = Builders<ConfigObservation>.Filter;
@@ -245,6 +263,7 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// </summary>
/// <param name="configObservationItem">El ConfigObservation a insertar en la base de datos.</param>
/// <returns>El ConfigObservation insertado, incluyendo su ID generado.</returns>
/// <!-- aidoc:v1 sig=0a96f47 body=ed8eb4c -->
public async Task<ConfigObservation> InsertOneAsyncAndReturn(ConfigObservation configObservationItem)
{
await Collection.InsertOneAsync(configObservationItem);
@@ -257,6 +276,8 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// </summary>
/// <param name="name">El nombre del ConfigObservation a buscar.</param>
/// <returns>Una lista de ConfigObservation que coinciden con el nombre proporcionado.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Summary claims a case-insensitive search ('insensible a mayúsculas y minúsculas'), but the code uses Builders.Eq which performs a case-sensitive equality match in MongoDB." -->
public async Task<List<ConfigObservation>> FindAllByName(string name)
{
var builder = Builders<ConfigObservation>.Filter;
@@ -279,6 +300,8 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// <param name="name">El nombre del ConfigObservation a buscar.</param>
/// <param name="originalName">El nombre original del ConfigObservation a buscar.</param>
/// <returns>El ConfigObservation que coincide con los parámetros proporcionados, o null si no se encuentra.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Summary claims the search is case-insensitive ('búsqueda insensible a mayúsculas y minúsculas'), but the code uses Builders<>.Eq which performs a case-sensitive equality match with no case-insensitive collation or regex." -->
public async Task<ConfigObservation?> GetSingleConfigObservationItem(string? code, string? codingSystem,
string? name, string? originalName)
{
@@ -301,6 +324,7 @@ public class ConfigObservationRepository : MongoRepository<ConfigObservation>, I
/// Si ya existen ConfigObservation en la base de datos, solo se insertan aquellos que faltan en comparación con la lista maestra.
/// </summary>
/// <returns></returns>
/// <!-- aidoc:v1 sig=ccdefcf body=2d99abd -->
public sealed override async Task InsertInitialLoad()
{
var stringNurseObs = _masterListServiceFactory.StringNurseObs();
@@ -9,6 +9,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Repository for managing ConfigPumps in MongoDB. Provides methods to retrieve, update, and delete pump configurations.
/// </summary>
/// <!-- aidoc:v1 sig=268862a -->
public class ConfigPumpsRepository : MongoRepository<ConfigPumps>, IConfigPumpsRepository
{
private readonly ApiSettings _apiSettings;
@@ -19,6 +20,7 @@ public class ConfigPumpsRepository : MongoRepository<ConfigPumps>, IConfigPumpsR
/// <param name="apiSettings">The API settings.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <exception cref="ArgumentNullException">Thrown when apiSettings is null.</exception>
/// <!-- aidoc:v1 sig=ee04ef2 body=d2b18a3 -->
public ConfigPumpsRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
{
if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
@@ -30,6 +32,7 @@ public class ConfigPumpsRepository : MongoRepository<ConfigPumps>, IConfigPumpsR
/// Gets the name of the MongoDB collection for ConfigPumps. Uses the value from API settings or defaults to "config_pumps".
/// </summary>
/// <returns>The name of the MongoDB collection for ConfigPumps.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=04254e5 -->
public override string GetCollectionName()
{
return _apiSettings.ConfigPumps ?? "config_pumps";
@@ -39,6 +42,8 @@ public class ConfigPumpsRepository : MongoRepository<ConfigPumps>, IConfigPumpsR
/// Retrieves all ConfigPumps documents from the MongoDB collection. Returns a list of ConfigPumps or null if no documents are found.
/// </summary>
/// <returns>A list of ConfigPumps or null if no documents are found.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "Documentation states the method returns null if no documents are found, but the code always returns a list (ToList() returns an empty list when no documents match, never null)." -->
public async Task<List<ConfigPumps>?> GetAllConfigs()
{
var result = await Collection.FindAsync(Builders<ConfigPumps>.Filter.Empty);
@@ -51,6 +56,7 @@ public class ConfigPumpsRepository : MongoRepository<ConfigPumps>, IConfigPumpsR
/// </summary>
/// <param name="id">The unique identifier of the ConfigPumps document.</param>
/// <returns>The ConfigPumps document if found, or null if not found.</returns>
/// <!-- aidoc:v1 sig=00c3a1c body=e64c9f9 -->
public async Task<ConfigPumps?> FindById(string id)
{
var result = await Collection.FindAsync(Builders<ConfigPumps>.Filter.Eq(x => x.Id, id));
@@ -65,6 +71,7 @@ public class ConfigPumpsRepository : MongoRepository<ConfigPumps>, IConfigPumpsR
/// </summary>
/// <param name="config">The ConfigPumps object containing the updated data.</param>
/// <returns>The updated ConfigPumps document if found, or null if not found.</returns>
/// <!-- aidoc:v1 sig=cc52f62 body=3d18e97 -->
public async Task<ConfigPumps?> UpdateConfig(ConfigPumps config)
{
var filter = Builders<ConfigPumps>.Filter.Eq("_id", config.Id);
@@ -80,6 +87,7 @@ public class ConfigPumpsRepository : MongoRepository<ConfigPumps>, IConfigPumpsR
/// </summary>
/// <param name="config">The ConfigPumps object to be deleted.</param>
/// <returns>True if the deletion was successful, false otherwise.</returns>
/// <!-- aidoc:v1 sig=4d3028e body=1b2f41a -->
public async Task<bool> DeleteConfig(ConfigPumps config)
{
var filter = Builders<ConfigPumps>.Filter.Eq("_id", config.Id);
@@ -9,6 +9,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Repository for managing ConfigUnits in MongoDB. Provides methods to retrieve and manipulate ConfigUnits data.
/// </summary>
/// <!-- aidoc:v1 sig=5a9f621 -->
public class ConfigUnitsRepository : MongoRepository<ConfigUnits>, IConfigUnitsRepository
{
private readonly ApiSettings _apiSettings;
@@ -19,6 +20,7 @@ public class ConfigUnitsRepository : MongoRepository<ConfigUnits>, IConfigUnitsR
/// <param name="apiSettings">The API settings.</param>
/// <param name="database">The MongoDB database.</param>
/// <exception cref="ArgumentNullException">Thrown when apiSettings is null.</exception>
/// <!-- aidoc:v1 sig=e6f329f body=d2b18a3 -->
public ConfigUnitsRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
{
if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
@@ -30,6 +32,7 @@ public class ConfigUnitsRepository : MongoRepository<ConfigUnits>, IConfigUnitsR
/// Gets the name of the MongoDB collection for ConfigUnits. This method retrieves the collection name from the API settings, or defaults to "config_units" if not specified.
/// </summary>
/// <returns>The name of the MongoDB collection for ConfigUnits.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=a6d4b9f -->
public override string GetCollectionName()
{
return _apiSettings.ConfigUnits ?? "config_units";
@@ -40,6 +43,7 @@ public class ConfigUnitsRepository : MongoRepository<ConfigUnits>, IConfigUnitsR
/// </summary>
/// <param name="id">The unique identifier of the ConfigUnits document.</param>
/// <returns>The ConfigUnits document if found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=5d21b10 body=63900d7 -->
public async Task<ConfigUnits?> FindById(string id)
{
var resutl = await Collection.FindAsync(Builders<ConfigUnits>.Filter.Eq(x => x.Id, id));
@@ -11,6 +11,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Repository for managing Device entities in MongoDB. Provides methods for finding devices by various attributes and updating device statistics.
/// </summary>
/// <!-- aidoc:v1 sig=8160c8b -->
public class DeviceRepository : MongoRepository<Device>, IDeviceRepository
{
private readonly ApiSettings _apiSettings;
@@ -20,6 +21,7 @@ public class DeviceRepository : MongoRepository<Device>, IDeviceRepository
/// </summary>
/// <param name="apiSettings">The API settings.</param>
/// <param name="database">The MongoDB database.</param>
/// <!-- aidoc:v1 sig=8e9392d body=d58addb -->
public DeviceRepository(ApiSettings apiSettings, IMongoDatabase database) : base(database)
{
_apiSettings = apiSettings;
@@ -29,6 +31,7 @@ public class DeviceRepository : MongoRepository<Device>, IDeviceRepository
/// Gets the name of the MongoDB collection for devices. The collection name is determined by the API settings, with a default value of "devices" if not specified.
/// </summary>
/// <returns>The name of the MongoDB collection for devices.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=8a1ceb4 -->
public override string GetCollectionName()
{
return _apiSettings.Devices ?? "devices";
@@ -40,6 +43,7 @@ public class DeviceRepository : MongoRepository<Device>, IDeviceRepository
/// The MacAddr index is unique, while the others are non-unique and created in the background.
/// </summary>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=4955da2 body=5d6df8e -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions { Background = true, Unique = true };
@@ -59,6 +63,7 @@ public class DeviceRepository : MongoRepository<Device>, IDeviceRepository
/// </summary>
/// <param name="deviceDtoMacAddr">The MAC address of the device to find.</param>
/// <returns>The device with the specified MAC address, or null if not found.</returns>
/// <!-- aidoc:v1 sig=e831bcc body=02399ff -->
public async Task<Device?> FindByMacAddr(string deviceDtoMacAddr)
{
return await Collection
@@ -71,6 +76,7 @@ public class DeviceRepository : MongoRepository<Device>, IDeviceRepository
/// </summary>
/// <param name="deviceDtoSerialNumber">The serial number of the device to find.</param>
/// <returns>The device with the specified serial number, or null if not found.</returns>
/// <!-- aidoc:v1 sig=d482bd7 body=6f0ac54 -->
public async Task<Device?> FindBySerialNumber(string deviceDtoSerialNumber)
{
return await Collection
@@ -83,6 +89,7 @@ public class DeviceRepository : MongoRepository<Device>, IDeviceRepository
/// </summary>
/// <param name="deviceDtoUuid">The UUID of the device to find.</param>
/// <returns>The device with the specified UUID, or null if not found.</returns>
/// <!-- aidoc:v1 sig=af1665c body=db4fc30 -->
public async Task<Device?> FindByUuid(string deviceDtoUuid)
{
return await Collection
@@ -95,6 +102,7 @@ public class DeviceRepository : MongoRepository<Device>, IDeviceRepository
/// </summary>
/// <param name="deviceDtoKey">The key of the device to find.</param>
/// <returns>The device with the specified key, or null if not found.</returns>
/// <!-- aidoc:v1 sig=a1e1740 body=65c4079 -->
public async Task<Device?> FindByKey(string deviceDtoKey)
{
return await Collection
@@ -109,6 +117,7 @@ public class DeviceRepository : MongoRepository<Device>, IDeviceRepository
/// <param name="id">The ID of the device to update.</param>
/// <param name="deviceExist">The existing DeviceDto object containing the updated statistics.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=0207e01 body=4ce9194 -->
public async Task UpdateDeviceStats(ObjectId id, DeviceDto deviceExist)
{
var update = Builders<Device>.Update
@@ -10,6 +10,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Repository for managing archived patient diagnoses in MongoDB. This repository provides methods for inserting, deleting, and indexing patient diagnosis records in the archive collection.
/// </summary>
/// <!-- aidoc:v1 sig=577bbca -->
public class DiagnosisArchiveRepository : MongoRepository<PatientDiagnosis>, IDiagnosisArchiveRepository
{
private readonly ApiSettings _apiSettings;
@@ -21,6 +22,7 @@ public class DiagnosisArchiveRepository : MongoRepository<PatientDiagnosis>, IDi
/// <param name="apiSettings"></param>
/// <param name="database"></param>
/// <exception cref="ArgumentNullException"></exception>
/// <!-- aidoc:v1 sig=7317890 body=d2b18a3 -->
public DiagnosisArchiveRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
{
if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
@@ -33,6 +35,7 @@ public class DiagnosisArchiveRepository : MongoRepository<PatientDiagnosis>, IDi
/// </summary>
/// <param name="patientDiagnosis">The patient diagnosis record to insert.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=078dbb7 body=e8b7555 -->
public override async Task InsertOneAsync(PatientDiagnosis patientDiagnosis)
{
await Collection.InsertOneAsync(patientDiagnosis);
@@ -43,6 +46,7 @@ public class DiagnosisArchiveRepository : MongoRepository<PatientDiagnosis>, IDi
/// </summary>
/// <param name="date">The date before which patient diagnosis records should be deleted.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=63daa66 body=6aa88ab -->
public async Task DeleteBeforeDate(DateTime date)
{
var filter = Builders<PatientDiagnosis>.Filter.Lt(po => po.Time, date);
@@ -55,6 +59,7 @@ public class DiagnosisArchiveRepository : MongoRepository<PatientDiagnosis>, IDi
/// </summary>
/// <param name="observations">The collection of patient diagnosis records to insert.</param>
/// <returns>The number of records successfully inserted.</returns>
/// <!-- aidoc:v1 sig=133455f body=c530ab0 -->
public async Task<long> InsertBatch(IEnumerable<PatientDiagnosis> observations)
{
var writes = new List<WriteModel<PatientDiagnosis>>();
@@ -71,6 +76,7 @@ public class DiagnosisArchiveRepository : MongoRepository<PatientDiagnosis>, IDi
/// If the API settings do not specify a collection name, a default name of "archive_patients_diagnosis" is used.
/// </summary>
/// <returns>The name of the MongoDB collection for archived patient diagnoses.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=4f8e6ac -->
public override string GetCollectionName()
{
return _apiSettings.ArchivePatientsDiagnosis ?? "archive_patients_diagnosis";
@@ -80,6 +86,7 @@ public class DiagnosisArchiveRepository : MongoRepository<PatientDiagnosis>, IDi
/// Creates indexes on the MongoDB collection for archived patient diagnoses to optimize query performance.
/// </summary>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=4955da2 body=f61edcf -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions<PatientDiagnosis> { Background = true, Unique = false };
@@ -11,6 +11,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Repository for managing patient diagnoses in a MongoDB collection. Provides methods for CRUD operations and querying diagnoses by patient ID and code.
/// </summary>
/// <!-- aidoc:v1 sig=4f19305 -->
public class DiagnosisRepository : MongoRepository<PatientDiagnosis>, IDiagnosisRepository
{
private readonly ApiSettings _apiSettings;
@@ -21,6 +22,7 @@ public class DiagnosisRepository : MongoRepository<PatientDiagnosis>, IDiagnosis
/// <param name="apiSettings">The API settings containing configuration for the repository.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <exception cref="ArgumentNullException">Thrown when the API settings are null.</exception>
/// <!-- aidoc:v1 sig=e5a1bd3 body=d2b18a3 -->
public DiagnosisRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
{
if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
@@ -31,6 +33,7 @@ public class DiagnosisRepository : MongoRepository<PatientDiagnosis>, IDiagnosis
/// Gets the name of the MongoDB collection for storing patient diagnoses. The collection name is determined by the API settings, and defaults to "patients_diagnosis" if not specified.
/// </summary>
/// <returns>The name of the MongoDB collection for patient diagnoses.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=feb8aa0 -->
public override string GetCollectionName()
{
return _apiSettings.PatientsDiagnosis ?? "patients_diagnosis";
@@ -41,6 +44,7 @@ public class DiagnosisRepository : MongoRepository<PatientDiagnosis>, IDiagnosis
/// </summary>
/// <param name="patientId">The ID of the patient whose diagnoses are to be retrieved.</param>
/// <returns>A list of patient diagnoses for the specified patient ID.</returns>
/// <!-- aidoc:v1 sig=29ab524 body=2b1e434 -->
public async Task<List<PatientDiagnosis>> GetByPatient(ObjectId patientId)
{
var filter = Builders<PatientDiagnosis>.Filter.Eq(ob => ob.PatientId, patientId);
@@ -55,6 +59,7 @@ public class DiagnosisRepository : MongoRepository<PatientDiagnosis>, IDiagnosis
/// </summary>
/// <param name="id">The ID of the patient diagnosis to delete.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=78c6c5d body=494b016 -->
public new async Task DeleteAsync(ObjectId id)
{
var filter = Builders<PatientDiagnosis>.Filter.Eq(t => t.Id, id);
@@ -66,6 +71,7 @@ public class DiagnosisRepository : MongoRepository<PatientDiagnosis>, IDiagnosis
/// </summary>
/// <param name="diagnosis">The patient diagnosis to insert.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=d69e886 body=fba3aaf -->
public override async Task InsertOneAsync(PatientDiagnosis diagnosis)
{
await Collection.InsertOneAsync(diagnosis);
@@ -76,6 +82,7 @@ public class DiagnosisRepository : MongoRepository<PatientDiagnosis>, IDiagnosis
/// </summary>
/// <param name="patientId">The ID of the patient whose diagnoses are to be deleted.</param>
/// <returns></returns>
/// <!-- aidoc:v1 sig=4776e51 body=1287abe -->
public async Task DeleteByPatientId(ObjectId patientId)
{
var filter = Builders<PatientDiagnosis>.Filter.Eq(po => po.PatientId, patientId);
@@ -91,6 +98,7 @@ public class DiagnosisRepository : MongoRepository<PatientDiagnosis>, IDiagnosis
/// <param name="code">The code of the diagnosis.</param>
/// <param name="codingSystem">The coding system of the diagnosis.</param>
/// <returns>The matching patient diagnosis, or null if not found.</returns>
/// <!-- aidoc:v1 sig=9870e04 body=960248f -->
public async Task<PatientDiagnosis?> FindByPatientIdAndCode(ObjectId patientId, string? code, string? codingSystem)
{
var builder = Builders<PatientDiagnosis>.Filter;
@@ -111,6 +119,7 @@ public class DiagnosisRepository : MongoRepository<PatientDiagnosis>, IDiagnosis
/// </summary>
/// <param name="patientId">The ID of the patient whose diagnoses are to be retrieved.</param>
/// <returns>An asynchronous cursor of patient diagnoses.</returns>
/// <!-- aidoc:v1 sig=98dc0d1 body=8f5c296 -->
public async Task<IAsyncCursor<PatientDiagnosis>> FindByPatientIdAsync(ObjectId patientId)
{
var filter = Builders<PatientDiagnosis>.Filter.Eq(ob => ob.PatientId, patientId);
@@ -126,6 +135,7 @@ public class DiagnosisRepository : MongoRepository<PatientDiagnosis>, IDiagnosis
/// <param name="id">The new patient ID to be set.</param>
/// <param name="oldId">The old patient ID to be replaced.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=72ce1ca body=b9b81e9 -->
public async Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId)
{
await UpdateManyObjectIdAsync(nameId, id, oldId);
@@ -135,6 +145,7 @@ public class DiagnosisRepository : MongoRepository<PatientDiagnosis>, IDiagnosis
/// Creates indexes for the patient diagnosis collection. This method ensures that the necessary indexes are created on the MongoDB collection to optimize query performance.
/// </summary>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=4955da2 body=5225318 -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions { Background = true, Unique = false };
@@ -17,6 +17,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Repository for managing Discharge entities in MongoDB. Provides methods for CRUD operations and specific queries related to discharges.
/// </summary>
/// <!-- aidoc:v1 sig=6c520ba -->
public class DischargeRepository : MongoRepository<Discharge>, IDischargeRepository
{
private readonly ApiSettings _apiSettings;
@@ -26,6 +27,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="apiSettings">The API settings containing configuration for the repository.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <!-- aidoc:v1 sig=37f77f4 body=12fddac -->
public DischargeRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
{
_apiSettings = apiSettings.Value;
@@ -35,6 +37,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// Gets the name of the MongoDB collection for discharges from the API settings.
/// </summary>
/// <returns>The name of the MongoDB collection for discharges.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=d8f9298 -->
public override string GetCollectionName()
{
return _apiSettings.Discharges;
@@ -45,6 +48,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="discharge">The discharge record to insert.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=e47013f body=e384f70 -->
public override async Task InsertOneAsync(Discharge discharge)
{
try
@@ -63,6 +67,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="id">The ID of the discharge record to delete.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc:v1 sig=3de1ad6 body=7e7d153 -->
public async Task Delete(ObjectId id)
{
try
@@ -83,6 +88,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// <param name="discharge">The discharge record to update.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <exception cref="ConflictException"></exception>
/// <!-- aidoc:v1 sig=1ecc041 body=d41cd7e -->
public async Task Update(Discharge discharge)
{
try
@@ -102,6 +108,8 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// <param name="id">The ID of the discharge record to update.</param>
/// <param name="unit">The new unit name to set.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc-review:v1 severity=high kind=stale_summary
/// "The summary claims 'If the update operation fails, an error is logged,' but the method body contains no try/catch, error handling, or logging — only an unawaited UpdateOneAsync call." -->
public async Task UpdateUnit(ObjectId id, string unit)
{
var filterBuilder = Builders<Discharge>.Filter;
@@ -119,6 +127,8 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// <param name="id">The ID of the discharge record to update.</param>
/// <param name="patient">The new patient information to set.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Summary claims 'If the update operation fails, an error is logged', but the code has no try-catch or logging mechanism — any failure would propagate as an exception." -->
public async Task UpdatePatient(ObjectId id, Patient patient)
{
var filterBuilder = Builders<Discharge>.Filter;
@@ -134,6 +144,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// Finds and retrieves all discharge records from the MongoDB collection. If an error occurs during retrieval, an error is logged and an empty list is returned.
/// </summary>
/// <returns>A task representing the asynchronous operation, containing a list of all discharge records.</returns>
/// <!-- aidoc:v1 sig=87546e9 body=77eea29 -->
public async Task<IEnumerable<Discharge>> FindAll()
{
try
@@ -153,6 +164,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="id">The ID of the discharge record to retrieve.</param>
/// <returns>A task representing the asynchronous operation, containing the discharge record if found, or null if not found or an error occurs.</returns>
/// <!-- aidoc:v1 sig=16a9670 body=05bd4d2 -->
public async Task<Discharge?> FindById(ObjectId id)
{
try
@@ -174,6 +186,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="unit">The unit name to search for.</param>
/// <returns>A task representing the asynchronous operation, containing a list of discharge records matching the specified unit name, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=26a3520 body=9cee09f -->
public async Task<IEnumerable<Discharge>?> FindByUnit(string unit)
{
try
@@ -195,6 +208,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="unitId">The ID of the unit to count discharge records for.</param>
/// <returns>A task representing the asynchronous operation, containing the count of discharge records matching the specified unit ID, or 0 if an error occurs.</returns>
/// <!-- aidoc:v1 sig=baa8175 body=1403f2e -->
public async Task<long> CountByUnitId(ObjectId unitId)
{
try
@@ -214,6 +228,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="destination">The destination to search for.</param>
/// <returns>A task representing the asynchronous operation, containing a list of discharge records matching the specified destination, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=7f6b4ab body=f403711 -->
public async Task<IEnumerable<Discharge>?> FindByDestination(string destination)
{
try
@@ -238,6 +253,10 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="unitIds">The IDs of the units to search for.</param>
/// <returns>A task representing the asynchronous operation, containing a list of discharge records matching the specified unit IDs, or null if an error occurs.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary states that on error an error is logged and null is returned, but the method has no try/catch and no logging; exceptions would propagate, not be swallowed and converted to null." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "The returns tag claims 'null if an error occurs', but the implementation never returns null on error (no exception handling); it only returns the ToListAsync result." -->
public async Task<IEnumerable<Discharge>?> GetDischargesByUnitIds(IEnumerable<ObjectId>? unitIds)
{
var filterUnit = Builders<Discharge>.Filter.In("unitId", unitIds);
@@ -249,6 +268,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="pocId">The ID of the Point of Care to search for.</param>
/// <returns>A task representing the asynchronous operation, containing a list of discharge records matching the specified Point of Care ID, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=13fd339 body=8de0a6c -->
public async Task<IEnumerable<Discharge>?> FindByPoCId(ObjectId pocId)
{
try
@@ -271,6 +291,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="service">The service to search for.</param>
/// <returns>A task representing the asynchronous operation, containing a list of discharge records matching the specified service, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=8f5cc53 body=fa9829a -->
public async Task<IEnumerable<Discharge>?> FindByService(string service)
{
try
@@ -292,6 +313,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="location">The patient location to search for.</param>
/// <returns>A task representing the asynchronous operation, containing the discharge record matching the specified patient location, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=d6f8db9 body=a619aca -->
public async Task<Discharge?> GetDischargeByLocation(PatientLocation location)
{
try
@@ -313,6 +335,8 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="id">The ID of the Point of Care to search for.</param>
/// <returns>A task representing the asynchronous operation, containing the discharge record matching the specified Point of Care ID, or null if an error occurs.</returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_returns
/// "Returns tag only mentions null in the error case, but FirstOrDefaultAsync also returns null when no matching discharge record is found" -->
public async Task<Discharge?> GetDischargeByPointOfCareId(ObjectId id)
{
try
@@ -337,6 +361,10 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// <param name="opt">The update option specifying the changes to be applied to the master list.</param>
/// <param name="typeName">The name of the master list type to be updated.</param>
/// <returns>A task representing the asynchronous operation, containing the updated discharge records, or an empty list if an error occurs.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary states the method 'performs updates accordingly', but the switch cases are empty (only comments) and no actual update logic is present in the code." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary claims 'If an error occurs during the update process, an error is logged and an empty list is returned', but there is no error handling or logging in the code, and the method always returns an empty list." -->
public Task<IEnumerable<Discharge>> UpdateMasterListOption(List<ObjectId> unitIds, UpdateOptionMasterListDto opt,
string typeName)
{
@@ -361,6 +389,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="unitId">The ID of the unit for which to delete discharge records.</param>
/// <returns>A task representing the asynchronous operation, containing true if the deletion was successful, or false if an error occurred.</returns>
/// <!-- aidoc:v1 sig=d4333b3 body=a16e555 -->
public async Task<bool> DeleteByUnitId(ObjectId unitId)
{
try
@@ -383,6 +412,12 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// <param name="opt">The update option specifying the changes to be applied to the master list.</param>
/// <param name="typeName">The name of the master list type to be updated.</param>
/// <returns>A task representing the asynchronous operation, containing the updated discharge records, or an empty list if an error occurs.</returns>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_param_role
/// "The <param name=\"opt\"> description calls it 'The update option specifying the changes to be applied to the master list', but the method is a delete operation (DeleteMasterListOption), so this should describe a delete option, not an update option." -->
/// <!-- aidoc-review:v1 severity=medium kind=wrong_param_role
/// "The <param name=\"typeName\"> description says 'The name of the master list type to be updated', but the method performs deletion, not update." -->
/// <!-- aidoc-review:v1 severity=medium kind=wrong_returns
/// "The <returns> description says 'containing the updated discharge records', but the method deletes and returns discharge records, it does not update them." -->
public Task<IEnumerable<Discharge>> DeleteMasterListOption(List<ObjectId> unitIds, OptionList opt, string typeName)
{
var isParsed = Enum.TryParse<MasterListType>(typeName, out var parsedTypeName);
@@ -406,6 +441,7 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// </summary>
/// <param name="patientId">The ID of the patient for which to retrieve the discharge record.</param>
/// <returns>A task representing the asynchronous operation, containing the discharge record if found, or null if an error occurs or the record is not found.</returns>
/// <!-- aidoc:v1 sig=e4173bb body=474ce38 -->
public async Task<Discharge?> GetByPatientId(ObjectId patientId)
{
try
@@ -428,6 +464,8 @@ public class DischargeRepository : MongoRepository<Discharge>, IDischargeReposit
/// If an error occurs during index creation, an error is logged.
/// </summary>
/// <returns></returns>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_summary
/// "Summary claims 'If an error occurs during index creation, an error is logged,' but the method body has no try/catch or logging code; error handling is delegated to MongoUtils.EnsureIndexes." -->
public override async Task CreateIndexes()
{
var optionsUq = new CreateIndexOptions<Discharge>
@@ -12,6 +12,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Repository for managing display card configurations in MongoDB. Provides methods to perform CRUD operations on CardConfig documents.
/// </summary>
/// <!-- aidoc:v1 sig=12ef408 -->
public class DisplayCardConfigRepository : MongoRepository<CardConfig>, IDisplayCardConfigRepository
{
private readonly ApiSettings _apiSettings;
@@ -23,6 +24,7 @@ public class DisplayCardConfigRepository : MongoRepository<CardConfig>, IDisplay
/// <param name="database">The MongoDB database instance.</param>
/// <param name="apiSettings">The API settings containing configuration for the repository.</param>
/// <param name="logger">The logger instance for logging repository operations.</param>
/// <!-- aidoc:v1 sig=0e57fcf body=7dde119 -->
public DisplayCardConfigRepository(
IMongoDatabase database,
ApiSettings apiSettings,
@@ -37,6 +39,7 @@ public class DisplayCardConfigRepository : MongoRepository<CardConfig>, IDisplay
/// Gets the name of the MongoDB collection for CardConfig documents, as specified in the API settings.
/// </summary>
/// <returns>The name of the MongoDB collection for CardConfig documents.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=9fe3e35 -->
public override string GetCollectionName()
{
return _apiSettings.DisplayCardConfig;
@@ -46,6 +49,8 @@ public class DisplayCardConfigRepository : MongoRepository<CardConfig>, IDisplay
/// Retrieves all CardConfig documents from the MongoDB collection and returns them as a list. Logs any exceptions that occur during the retrieval process.
/// </summary>
/// <returns>A task representing the asynchronous operation, containing a list of all CardConfig documents.</returns>
/// <!-- aidoc-review:v1 severity=high kind=mentions_removed_behavior
/// "Summary claims the method 'Logs any exceptions that occur during the retrieval process,' but the code body contains no exception handling or logging." -->
public async Task<List<CardConfig>> GetAll()
{
var result = await Collection.Find(Builders<CardConfig>.Filter.Empty).ToListAsync();
@@ -57,6 +62,7 @@ public class DisplayCardConfigRepository : MongoRepository<CardConfig>, IDisplay
/// </summary>
/// <param name="configId">The unique identifier of the CardConfig document.</param>
/// <returns>A task representing the asynchronous operation, containing the CardConfig document if found, or null if not found or an error occurs.</returns>
/// <!-- aidoc:v1 sig=f4374bb body=2b6bbf9 -->
public async Task<CardConfig?> GetById(ObjectId configId)
{
try
@@ -76,6 +82,7 @@ public class DisplayCardConfigRepository : MongoRepository<CardConfig>, IDisplay
/// </summary>
/// <param name="config">The CardConfig document to insert.</param>
/// <returns>A task representing the asynchronous operation, containing the inserted CardConfig document if successful, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=2193380 body=b92e5d6 -->
public async Task<CardConfig?> InsertOneAsyncAndReturn(CardConfig config)
{
try
@@ -98,6 +105,7 @@ public class DisplayCardConfigRepository : MongoRepository<CardConfig>, IDisplay
/// </summary>
/// <param name="config">The CardConfig document to update.</param>
/// <returns>A task representing the asynchronous operation, containing an UpdateResponse with the number of modified documents and the updated document.</returns>
/// <!-- aidoc:v1 sig=5309b51 body=5aadf60 -->
public async Task<UpdateResponse<CardConfig?>> UpdateOne(CardConfig? config)
{
try
@@ -124,6 +132,7 @@ public class DisplayCardConfigRepository : MongoRepository<CardConfig>, IDisplay
/// </summary>
/// <param name="configId">The unique identifier of the CardConfig document to delete.</param>
/// <returns>A task representing the asynchronous operation, containing the deleted CardConfig document if successful, or null if not found or an error occurs.</returns>
/// <!-- aidoc:v1 sig=b415d24 body=47fbf6b -->
public async Task<CardConfig?> DeleteOne(ObjectId configId)
{
return await DeleteAsync(configId);
@@ -136,6 +145,7 @@ public class DisplayCardConfigRepository : MongoRepository<CardConfig>, IDisplay
/// <param name="resultId">The unique identifier of the result.</param>
/// <returns>A task representing the asynchronous operation, containing the updated CardConfig document if successful, or null if not found or an error occurs. </returns>
/// <exception cref="NotImplementedException"></exception>
/// <!-- aidoc:v1 sig=385c445 body=bfa6f2f -->
public Task<object> UpdateCardConfigId(ObjectId? displayConfigId, ObjectId? resultId)
{
throw new NotImplementedException();
@@ -12,6 +12,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Repository for managing ChartConfig in MongoDB. Provides methods to retrieve and manipulate ChartConfig data.
/// </summary>
/// <!-- aidoc:v1 sig=22edc0e -->
public class DisplayChartConfigRepository : MongoRepository<ChartConfig>, IDisplayChartConfigRepository
{
private readonly ApiSettings _apiSettings;
@@ -24,6 +25,7 @@ public class DisplayChartConfigRepository : MongoRepository<ChartConfig>, IDispl
/// <param name="database">The MongoDB database instance.</param>
/// <param name="apiSettings">The API settings instance.</param>
/// <param name="logger">The logger instance.</param>
/// <!-- aidoc:v1 sig=9ddd533 body=7dde119 -->
public DisplayChartConfigRepository(IMongoDatabase database, ApiSettings apiSettings,
ILogger<DisplayChartConfigRepository> logger) : base(database)
{
@@ -35,6 +37,7 @@ public class DisplayChartConfigRepository : MongoRepository<ChartConfig>, IDispl
/// Gets the name of the MongoDB collection for ChartConfig. This method retrieves the collection name from the API settings.
/// </summary>
/// <returns>The name of the MongoDB collection for ChartConfig.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=0d27cbe -->
public override string GetCollectionName()
{
return _apiSettings.DisplayChartConfig;
@@ -44,6 +47,7 @@ public class DisplayChartConfigRepository : MongoRepository<ChartConfig>, IDispl
/// Retrieves all ChartConfig documents from the MongoDB collection. This method returns a list of ChartConfig objects representing all the configurations stored in the database.
/// </summary>
/// <returns>A list of ChartConfig objects representing all the configurations stored in the database.</returns>
/// <!-- aidoc:v1 sig=c0c01a0 body=014de50 -->
public async Task<List<ChartConfig>> GetAll()
{
var result = await Collection.Find(Builders<ChartConfig>.Filter.Empty).ToListAsync();
@@ -55,6 +59,7 @@ public class DisplayChartConfigRepository : MongoRepository<ChartConfig>, IDispl
/// </summary>
/// <param name="configId">The unique identifier of the ChartConfig document.</param>
/// <returns>The ChartConfig object if found, or null if no matching document is found.</returns>
/// <!-- aidoc:v1 sig=6225aa4 body=e406da3 -->
public async Task<ChartConfig?> GetById(ObjectId configId)
{
try
@@ -75,6 +80,7 @@ public class DisplayChartConfigRepository : MongoRepository<ChartConfig>, IDispl
/// </summary>
/// <param name="config">The ChartConfig object to be inserted into the MongoDB collection.</param>
/// <returns>The inserted ChartConfig object if successful, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=14ecb27 body=b92e5d6 -->
public async Task<ChartConfig?> InsertOneAsyncAndReturn(ChartConfig config)
{
try
@@ -97,6 +103,7 @@ public class DisplayChartConfigRepository : MongoRepository<ChartConfig>, IDispl
/// </summary>
/// <param name="config">The ChartConfig object containing the updated data.</param>
/// <returns>An UpdateResponse object containing the number of changes made and the updated ChartConfig document.</returns>
/// <!-- aidoc:v1 sig=6322c8a body=dcdf910 -->
public async Task<UpdateResponse<ChartConfig?>> UpdateOne(ChartConfig? config)
{
try
@@ -129,6 +136,8 @@ public class DisplayChartConfigRepository : MongoRepository<ChartConfig>, IDispl
/// </summary>
/// <param name="configId">ChartConfig Id to be deleted </param>
/// <returns></returns>
/// <!-- aidoc-review:v1 severity=low kind=missing_returns
/// "<returns> tag is empty; method returns Task<ChartConfig?> (the deleted ChartConfig or null)" -->
public async Task<ChartConfig?> DeleteOne(ObjectId configId)
{
return await DeleteAsync(configId);
@@ -22,6 +22,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repository implementation for managing DisplayConfig entities in MongoDB.
/// Provides CRUD operations and specialized queries for display configurations.
/// </summary>
/// <!-- aidoc:v1 sig=ca069f4 -->
public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayConfigRepository
{
private readonly ApiSettings _apiSettings;
@@ -35,6 +36,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="apiSettings">API settings containing collection names configuration.</param>
/// <param name="logger">Logger for repository operations.</param>
/// <param name="unitRepository">Repository for unit-related operations.</param>
/// <!-- aidoc:v1 sig=a0aa8ef body=0dfcbb0 -->
public DisplayConfigRepository(
IMongoDatabase database,
ApiSettings apiSettings,
@@ -50,6 +52,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// Gets the name of the collection for display configurations.
/// </summary>
/// <returns>The collection name from API settings.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=f8787a2 -->
public override string GetCollectionName()
{
return _apiSettings.DisplaysConfig;
@@ -59,6 +62,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// Retrieves all display configurations from the database.
/// </summary>
/// <returns>A list of all DisplayConfig entities.</returns>
/// <!-- aidoc:v1 sig=fb4ed8e body=24446a1 -->
public async Task<List<DisplayConfig>> GetAll()
{
var result = await Collection.Find(Builders<DisplayConfig>.Filter.Empty).ToListAsync();
@@ -71,6 +75,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="filter">The pagination and filtering parameters.</param>
/// <returns>A fluent queryable for DisplayConfigSummary results.</returns>
/// <exception cref="BadRequestException">Thrown when the text filter exceeds 100 characters.</exception>
/// <!-- aidoc:v1 sig=02e1b9c body=5dc4416 -->
public IFindFluent<DisplayConfig, DisplayConfigSummary> GetAllPaginated(PaginationFilter filter)
{
var filterBuilder = Builders<DisplayConfig>.Filter;
@@ -116,6 +121,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// </summary>
/// <param name="type">The display type to filter by.</param>
/// <returns>A list of DisplayConfig entities matching the specified type.</returns>
/// <!-- aidoc:v1 sig=8122d6c body=0e1c2e7 -->
public async Task<List<DisplayConfig>> GetByType(DisplayConfigEnums.DisplayType type)
{
var filter = Builders<DisplayConfig>.Filter.Eq(p => p.Type, type);
@@ -129,6 +135,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// </summary>
/// <param name="id">The ObjectId of the display configuration to retrieve.</param>
/// <returns>The DisplayConfig with related data, or null if not found.</returns>
/// <!-- aidoc:v1 sig=a9a2204 body=4378765 -->
public async Task<DisplayConfig?> GetById(ObjectId id)
{
try
@@ -231,6 +238,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// </summary>
/// <param name="type">The display type to search for.</param>
/// <returns>The default DisplayConfig for the specified type, or null if not found.</returns>
/// <!-- aidoc:v1 sig=2078a2a body=724ce64 -->
public async Task<DisplayConfig?> GetDefault(DisplayConfigEnums.DisplayType type)
{
var filter = Builders<DisplayConfig>.Filter.And(
@@ -248,6 +256,8 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="config">The DisplayConfig to insert.</param>
/// The inserted DisplayConfig, or null if insertion fails.
/// <returns></returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_returns
/// "The <returns> tag is empty; the description 'The inserted DisplayConfig, or null if insertion fails.' is placed outside the tag, making the returns documentation structurally malformed." -->
public async Task<DisplayConfig?> InsertOneAsyncAndReturn(DisplayConfig config)
{
try
@@ -268,6 +278,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="displayConfigId">The ObjectId of the display configuration to update.</param>
/// <param name="newDisplayConfig">The new SmartDisplay configuration to apply.</param>
/// <returns>The updated SmartDisplay configuration, or null if update fails.</returns>
/// <!-- aidoc:v1 sig=58bdfe0 body=590507f -->
public async Task<SmartDisplay?> UpdateSmartDisplay(ObjectId displayConfigId, SmartDisplay? newDisplayConfig)
{
try
@@ -315,6 +326,8 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="colorConfig">The new ColorConfig to apply.</param>
/// <returns>True if the update was successful; otherwise, false.</returns>
/// <exception cref="Exception">Throws an exception if MongoDB update fails.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "The documentation claims the method throws an exception if the MongoDB update fails, but the method catches all exceptions internally and returns false instead of throwing." -->
public async Task<bool> UpdateConfigColor(ObjectId objectIdConfigDisplay, ColorConfig colorConfig)
{
var filter = Builders<DisplayConfig>.Filter.Eq("Id", objectIdConfigDisplay);
@@ -362,6 +375,8 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="headerConfig">The new HeaderConfig to apply.</param>
/// <returns>True if the update was successful; otherwise, false.</returns>
/// <exception cref="Exception">Throws an exception if MongoDB update fails.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "The method catches all exceptions internally and returns false rather than throwing; the documented exception is never propagated to callers." -->
public async Task<bool> UpdateHeaderConfig(ObjectId objectIdConfigDisplay, HeaderConfig headerConfig)
{
var filter = Builders<DisplayConfig>.Filter.Eq("Id", objectIdConfigDisplay);
@@ -419,6 +434,8 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="bannerItems">The list of banner items to set.</param>
/// <returns>True if the update was successful; otherwise, false.</returns>
/// <exception cref="Exception">Throws an exception if MongoDB update fails.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "The method catches all exceptions and returns false; it never throws an exception as documented." -->
public async Task<bool> UpdateSetHomeBanner(ObjectId objectIdConfigDisplay, List<BannerItem> bannerItems)
{
var filter = Builders<DisplayConfig>.Filter.Eq("Id", objectIdConfigDisplay);
@@ -445,6 +462,8 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="baseConfig">The base DisplayConfig with updated values.</param>
/// <returns>True if the update was successful; otherwise, false.</returns>
/// <exception cref="Exception">Throws an exception if MongoDB update fails.</exception>
/// <!-- aidoc-review:v1 severity=high kind=extra_exception
/// "The method catches all exceptions internally (try/catch logs and returns false) and never propagates an exception to the caller, yet the doc claims it throws Exception on MongoDB update failure." -->
public async Task<bool> UpdateBaseConfig(ObjectId objectIdConfigDisplay, DisplayConfig baseConfig)
{
var filter = Builders<DisplayConfig>.Filter.Eq("Id", objectIdConfigDisplay);
@@ -475,6 +494,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="newDisplayConfig">The new DisplayNurseDto configuration to apply.</param>
/// <param name="nurseObs">List of observation names to mark as "last".</param>
/// <returns>The updated DisplayNurse configuration, or null if update fails.</returns>
/// <!-- aidoc:v1 sig=0cb9b52 body=d8fcae3 -->
public async Task<DisplayNurse?> UpdateDisplayNurse(ObjectId displayConfigId, DisplayNurseDto? newDisplayConfig,
List<string> nurseObs)
{
@@ -537,6 +557,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="objectIdConfigDisplay">The ObjectId of the display configuration to update.</param>
/// <param name="name">The new hospital name.</param>
/// <returns>True if the update was successful; otherwise, false.</returns>
/// <!-- aidoc:v1 sig=d760b75 body=7083954 -->
public async Task<bool> UpdateDisplayConfigHospitalName(ObjectId objectIdConfigDisplay, string name)
{
var filter = Builders<DisplayConfig>.Filter.Eq(c => c.Id, objectIdConfigDisplay);
@@ -563,6 +584,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="objectIdConfigDisplay">The ObjectId of the display configuration to update.</param>
/// <param name="fields">The new list of fields to set.</param>
/// <returns>True if the update was successful; otherwise, false.</returns>
/// <!-- aidoc:v1 sig=43fa539 body=cc10b03 -->
public async Task<bool> UpdateFieldList(ObjectId objectIdConfigDisplay, List<Field> fields)
{
var filter = Builders<DisplayConfig>.Filter.Eq(x => x.Id, objectIdConfigDisplay);
@@ -578,6 +600,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="unitId">The ObjectId of the unit.</param>
/// <param name="displayType">The type of display configuration to retrieve.</param>
/// <returns>The default DisplayConfig for the unit, or null if not found.</returns>
/// <!-- aidoc:v1 sig=af33a33 body=295e51e -->
public async Task<DisplayConfig?> GetDefaultByUnitIdAndType(ObjectId unitId,
DisplayConfigEnums.DisplayType displayType)
{
@@ -602,6 +625,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// </summary>
/// <param name="objectIdConfigDisplay">The ObjectId of the display configuration to delete.</param>
/// <returns>The deleted DisplayConfig, or null if not found.</returns>
/// <!-- aidoc:v1 sig=cb87e31 body=36ac5e8 -->
public async Task<DisplayConfig?> DeleteDisplayConfig(ObjectId objectIdConfigDisplay)
{
return await DeleteAsync(objectIdConfigDisplay);
@@ -611,6 +635,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// Retrieves all display configurations in compact format (minimal response).
/// </summary>
/// <returns>A list of DisplayConfigMinimalResponse containing Id, Hospital, and Type.</returns>
/// <!-- aidoc:v1 sig=5f61162 body=223c235 -->
public Task<List<DisplayConfigMinimalResponse>> GetAllCompact()
{
var filter = Builders<DisplayConfig>.Filter.Empty;
@@ -629,6 +654,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// </summary>
/// <param name="cardConfigId">The ObjectId of the card configuration.</param>
/// <returns>A list of ObjectIds for display configurations using the specified card config.</returns>
/// <!-- aidoc:v1 sig=019036b body=4e73250 -->
public async Task<List<ObjectId>> GetAllByCardConfigId(ObjectId cardConfigId)
{
var filter = Builders<DisplayConfig>.Filter.Eq(d => d.CardConfigId, cardConfigId);
@@ -645,6 +671,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// </summary>
/// <param name="cardConfigId">The ObjectId of the card configuration.</param>
/// <returns>A list of ObjectIds for display configurations using the specified card config in main or rotating layout.</returns>
/// <!-- aidoc:v1 sig=295400b body=1b55ad2 -->
public async Task<List<ObjectId>> GetAllByCardConfigIdAndRotating(ObjectId cardConfigId)
{
var mainFilter = Builders<DisplayConfig>.Filter.Eq(d => d.CardConfigId, cardConfigId);
@@ -669,6 +696,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="displayConfigId">The ObjectId of the display configuration to update.</param>
/// <param name="resultId">The new card configuration ID to set.</param>
/// <returns>True if the update was successful; otherwise, false.</returns>
/// <!-- aidoc:v1 sig=bdfb090 body=66dd0a1 -->
public async Task<bool> UpdateCardConfigId(ObjectId? displayConfigId, ObjectId? resultId)
{
var filter = Builders<DisplayConfig>.Filter.Eq(x => x.Id, displayConfigId);
@@ -684,6 +712,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="displayConfigId">The ObjectId of the display configuration to update.</param>
/// <param name="newChartIdToAdd">The new chart configuration ID to add.</param>
/// <returns>True if the update was successful; otherwise, false.</returns>
/// <!-- aidoc:v1 sig=1b8d34f body=b651a1f -->
public async Task<bool> AddChartId(ObjectId? displayConfigId, ObjectId newChartIdToAdd)
{
var filter = Builders<DisplayConfig>.Filter.Eq(x => x.Id, displayConfigId);
@@ -700,6 +729,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="deletedId">The ObjectId of the chart configuration that was deleted.</param>
/// <returns>The MongoDB UpdateResult indicating the number of modified documents.</returns>
/// <exception cref="Exception">Throws an exception if MongoDB operation fails.</exception>
/// <!-- aidoc:v1 sig=075b13a body=f79af77 -->
public async Task<UpdateResult> UpdateDeletedChartConfig(ObjectId deletedId)
{
try
@@ -723,6 +753,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="objectIdConfigChart">The ObjectId of the chart configuration.</param>
/// <returns>Always throws NotImplementedException.</returns>
/// <exception cref="NotImplementedException">This method is not implemented.</exception>
/// <!-- aidoc:v1 sig=a5f05a4 body=bfa6f2f -->
public Task<ChartConfig> GetChartConfig(ObjectId objectIdConfigChart)
{
throw new NotImplementedException();
@@ -734,6 +765,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="displayConfigId">The ObjectId of the display configuration to update.</param>
/// <param name="resultId">The new detail configuration ID to set.</param>
/// <returns>True if the update was successful; otherwise, false.</returns>
/// <!-- aidoc:v1 sig=4dd76a3 body=4d42278 -->
public async Task<bool> UpdateDetailConfigId(ObjectId? displayConfigId, ObjectId? resultId)
{
var filter = Builders<DisplayConfig>.Filter.Eq(x => x.Id, displayConfigId);
@@ -748,6 +780,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// </summary>
/// <param name="baseConfigId">The ObjectId of the detail configuration.</param>
/// <returns>A list of ObjectIds for display configurations using the specified detail config.</returns>
/// <!-- aidoc:v1 sig=63a6ce8 body=8cc75f6 -->
public async Task<List<ObjectId>> GetAllByCardDetailConfigId(ObjectId baseConfigId)
{
var filter = Builders<DisplayConfig>.Filter.Eq(d => d.DetailConfigId, baseConfigId);
@@ -768,6 +801,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// - SmartDisplay
/// - StandarDisplay
/// </remarks>
/// <!-- aidoc:v1 sig=ccdefcf body=119a973 -->
public sealed override async Task InsertInitialLoad()
{
// 1. Obtener todos los valores y castear al tipo IEnumerable<DisplayType>
@@ -828,6 +862,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="newDisplayConfig">The DisplayNurseDto configuration to extract fields from.</param>
/// <param name="nurseObs">List of observation names to mark as "last" priority.</param>
/// <returns>A list of Field objects with extracted observation names.</returns>
/// <!-- aidoc:v1 sig=be49f7a body=ac425f2 -->
private List<Field> ExtractObservationFields(DisplayNurseDto newDisplayConfig, List<string> nurseObs)
{
var fieldSet = new HashSet<string>();
@@ -859,6 +894,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="newDisplayConfig">The JSON string to search for observation names.</param>
/// <param name="regex">The regex pattern to match observation name arrays.</param>
/// <param name="fieldSet">The hash set to populate with field names.</param>
/// <!-- aidoc:v1 sig=04f2381 body=6fed3f0 -->
private void FillHashSet(string newDisplayConfig, Regex regex, HashSet<string> fieldSet)
{
var matches = regex.Matches(newDisplayConfig);
@@ -877,6 +913,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// </summary>
/// <param name="cells">The list of cells to extract from.</param>
/// <param name="fieldSet">The hash set to populate with field names.</param>
/// <!-- aidoc:v1 sig=dc14082 body=a8faa74 -->
private void ExtractFromCells(List<Cell>? cells, HashSet<string> fieldSet)
{
if (cells is null)
@@ -900,6 +937,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// </summary>
/// <param name="cells">The list of detail cells to extract from.</param>
/// <param name="fieldSet">The hash set to populate with field names.</param>
/// <!-- aidoc:v1 sig=263c487 body=3b85da1 -->
private void ExtractFromDetailsCells(List<CellDetails>? cells, HashSet<string> fieldSet)
{
if (cells is null)
@@ -924,6 +962,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// <param name="filters">List of filter definitions to apply.</param>
/// <param name="sort">Sort definition for the query results.</param>
/// <returns>A fluent queryable for DisplayConfigSummary.</returns>
/// <!-- aidoc:v1 sig=2b4f3c2 body=ceac316 -->
private IFindFluent<DisplayConfig, DisplayConfigSummary> CreateFindFluentMinimal(
List<FilterDefinition<DisplayConfig>> filters,
SortDefinition<DisplayConfig> sort)
@@ -948,6 +987,7 @@ public class DisplayConfigRepository : MongoRepository<DisplayConfig>, IDisplayC
/// </summary>
/// <param name="baseConfig">The base DisplayConfig with values to update.</param>
/// <returns>A tuple containing list of update definitions and list of field names.</returns>
/// <!-- aidoc:v1 sig=9aca42d body=1c04095 -->
private (List<UpdateDefinition<DisplayConfig>> Updates, List<string> Fields) GetBaseUpdateDefinition(
DisplayConfig baseConfig)
{
@@ -13,6 +13,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repository implementation for managing CardDetailsConfig entities in MongoDB.
/// Provides CRUD operations for display detail configurations used in nurse and smart displays.
/// </summary>
/// <!-- aidoc:v1 sig=34c7058 -->
public class DisplayDetailConfigRepository : MongoRepository<CardDetailsConfig>, IDisplayDetailConfigRepository
{
private readonly ApiSettings _apiSettings;
@@ -24,6 +25,7 @@ public class DisplayDetailConfigRepository : MongoRepository<CardDetailsConfig>,
/// <param name="database">The MongoDB database instance.</param>
/// <param name="apiSettings">API settings containing collection names configuration.</param>
/// <param name="logger">Logger for repository operations.</param>
/// <!-- aidoc:v1 sig=ad18f30 body=7dde119 -->
public DisplayDetailConfigRepository(
IMongoDatabase database,
ApiSettings apiSettings,
@@ -38,6 +40,7 @@ public class DisplayDetailConfigRepository : MongoRepository<CardDetailsConfig>,
/// Gets the name of the collection for display detail configurations.
/// </summary>
/// <returns>The collection name from API settings.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=957e9fe -->
public override string GetCollectionName()
{
return _apiSettings.DisplayDetailConfig;
@@ -47,6 +50,7 @@ public class DisplayDetailConfigRepository : MongoRepository<CardDetailsConfig>,
/// Retrieves all display detail configurations from the database.
/// </summary>
/// <returns>A list of all CardDetailsConfig entities.</returns>
/// <!-- aidoc:v1 sig=7f19149 body=555d3e4 -->
public async Task<List<CardDetailsConfig>> GetAll()
{
var result = await Collection.Find(Builders<CardDetailsConfig>.Filter.Empty).ToListAsync();
@@ -59,6 +63,8 @@ public class DisplayDetailConfigRepository : MongoRepository<CardDetailsConfig>,
/// <param name="configId">The ObjectId of the detail configuration to retrieve.</param>
/// <returns>The CardDetailsConfig if found; otherwise, null.</returns>
/// <exception cref="Exception">Throws an exception if MongoDB query fails; returns null instead.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "The method catches all exceptions and returns null; it never throws. The exception tag incorrectly states 'Throws an exception if MongoDB query fails' and is internally contradictory ('returns null instead')." -->
public async Task<CardDetailsConfig?> GetById(ObjectId configId)
{
try
@@ -78,6 +84,7 @@ public class DisplayDetailConfigRepository : MongoRepository<CardDetailsConfig>,
/// </summary>
/// <param name="config">The CardDetailsConfig to insert.</param>
/// <returns>The inserted CardDetailsConfig, or null if insertion fails.</returns>
/// <!-- aidoc:v1 sig=269dde2 body=b92e5d6 -->
public async Task<CardDetailsConfig?> InsertOneAsyncAndReturn(CardDetailsConfig config)
{
try
@@ -98,6 +105,8 @@ public class DisplayDetailConfigRepository : MongoRepository<CardDetailsConfig>,
/// <param name="config">The CardDetailsConfig with updated values.</param>
/// <returns>An UpdateResponse containing the modified count and the updated document.</returns>
/// <exception cref="Exception">Throws an exception if MongoDB update fails; returns UpdateResponse with null document.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "The <exception> tag states the method throws an exception on MongoDB failure, but the catch block catches Exception and never rethrows it; the method always returns an UpdateResponse." -->
public async Task<UpdateResponse<CardDetailsConfig?>> UpdateOne(CardDetailsConfig? config)
{
try
@@ -130,6 +139,7 @@ public class DisplayDetailConfigRepository : MongoRepository<CardDetailsConfig>,
/// </summary>
/// <param name="configId">The ObjectId of the configuration to delete.</param>
/// <returns>The deleted CardDetailsConfig if found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=84fe430 body=47fbf6b -->
public async Task<CardDetailsConfig?> DeleteOne(ObjectId configId)
{
return await DeleteAsync(configId);
@@ -142,6 +152,8 @@ public class DisplayDetailConfigRepository : MongoRepository<CardDetailsConfig>,
/// <param name="resultId">The new reference ID to set.</param>
/// <returns>Always throws NotImplementedException.</returns>
/// <exception cref="NotImplementedException">This method is not implemented.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=stale_summary
/// "Summary only mentions updating 'the display configuration ID reference' but the method (UpdateCardConfigId) also takes a resultId parameter, indicating it updates more than just the display config ID" -->
public Task<object> UpdateCardConfigId(ObjectId? displayConfigId, ObjectId? resultId)
{
throw new NotImplementedException();
@@ -17,6 +17,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repository implementation for managing Display entities in MongoDB.
/// Provides CRUD operations and specialized queries for display devices.
/// </summary>
/// <!-- aidoc:v1 sig=4489fa0 -->
public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
{
#region Properties
@@ -34,6 +35,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// <param name="apiSettings">API settings containing collection names configuration.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <param name="logger">Logger for repository operations.</param>
/// <!-- aidoc:v1 sig=602ae85 body=8a9d2fd -->
public DisplayRepository(
IOptions<ApiSettings> apiSettings,
IMongoDatabase database,
@@ -53,6 +55,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// Creates the necessary indexes for the Display collection.
/// Creates indexes on displayConfigId and unitId fields for improved query performance.
/// </summary>
/// <!-- aidoc:v1 sig=4955da2 body=e61cb51 -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions<Display> { Background = true, Unique = false };
@@ -74,6 +77,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// Gets the name of the collection for displays.
/// </summary>
/// <returns>The collection name from API settings.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=1415d9e -->
public override string GetCollectionName()
{
return _apiSettings.Displays;
@@ -83,6 +87,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// Retrieves all displays from the database.
/// </summary>
/// <returns>A list of all Display entities.</returns>
/// <!-- aidoc:v1 sig=f108028 body=b55a64a -->
public async Task<List<Display>> GetAll()
{
var result = await Collection.Find(Builders<Display>.Filter.Empty).ToListAsync();
@@ -96,6 +101,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// <param name="filter">The pagination and filtering parameters.</param>
/// <returns>A fluent queryable for Display results.</returns>
/// <exception cref="BadRequestException">Thrown when the text filter exceeds 100 characters.</exception>
/// <!-- aidoc:v1 sig=2c97614 body=82ace38 -->
public IFindFluent<Display, Display> GetPaginatedDisplays(PaginationFilter filter)
{
var filterBuilder = Builders<Display>.Filter;
@@ -148,6 +154,8 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// <param name="filters">List of filter definitions to apply.</param>
/// <param name="sort">Sort definition for the query results.</param>
/// <returns>A fluent queryable for Display results.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary says 'paginated displays' but the code only performs Find and Sort with no Skip/Limit pagination logic." -->
private IFindFluent<Display, Display> CreateFindFluent(List<FilterDefinition<Display>> filters,
SortDefinition<Display> sort)
{
@@ -162,6 +170,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// </summary>
/// <param name="pointOfCare">The PointOfCare to filter by.</param>
/// <returns>A list of Display entities associated with the point of care.</returns>
/// <!-- aidoc:v1 sig=ad8af85 body=814934a -->
public async Task<List<Display>> GetByPointOfCare(PointOfCare pointOfCare)
{
var filter = Builders<Display>.Filter.AnyEq(x => x.PointOfCareIdList, pointOfCare.Id);
@@ -174,6 +183,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// </summary>
/// <param name="name">The name of the display to retrieve.</param>
/// <returns>The Display if found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=58df1bb body=fbf8613 -->
public async Task<Display?> GetByName(string name)
{
var result = await Collection.FindAsync(Builders<Display>.Filter.Eq(p => p.Name, name));
@@ -185,6 +195,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// </summary>
/// <param name="id">The ObjectId of the display to retrieve.</param>
/// <returns>The Display if found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=06fe2a7 body=9ea9cc7 -->
public async Task<Display?> GetById(ObjectId id)
{
var result = await Collection.FindAsync(Builders<Display>.Filter.Eq(p => p.Id, id));
@@ -197,6 +208,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// </summary>
/// <param name="id">The ObjectId of the display to retrieve.</param>
/// <returns>The Display with DisplayConfig populated if found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=9707594 body=ef3813d -->
public async Task<Display?> GetByIdWithConfigDisplay(ObjectId id)
{
var pipeline = new BsonDocument[]
@@ -225,6 +237,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// </summary>
/// <param name="id">The ObjectId of the unit.</param>
/// <returns>A list of Display entities associated with the unit.</returns>
/// <!-- aidoc:v1 sig=30d0bf1 body=d267dcd -->
public async Task<List<Display>> GetByUnitId(ObjectId id)
{
var filter = Builders<Display>.Filter.Eq(p => p.UnitId, id);
@@ -238,6 +251,8 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// <param name="unitId">The ObjectId of the unit.</param>
/// <returns>The count of displays for the unit, or 0 if an error occurs.</returns>
/// <exception cref="Exception">Logs errors and returns 0 on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_exception
/// "Method catches Exception internally and returns 0; it does not throw Exception. The <exception> tag misleads readers about thrown exceptions." -->
public async Task<long> CountByUnitId(ObjectId unitId)
{
try
@@ -256,6 +271,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// </summary>
/// <param name="id">The ObjectId of the display configuration.</param>
/// <returns>A list of Display entities using the specified configuration.</returns>
/// <!-- aidoc:v1 sig=55e6b45 body=769064e -->
public async Task<List<Display>> GetByConfigId(ObjectId id)
{
var result = await Collection.FindAsync(Builders<Display>.Filter.Eq(p => p.DisplayConfigId, id));
@@ -269,6 +285,8 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// <param name="configId">The ObjectId of the card configuration.</param>
/// <returns>A list of Display entities using the specified card config, or empty list on error.</returns>
/// <exception cref="Exception">Logs errors and returns empty list on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The <exception cref=\"Exception\"> tag documents an exception that the method catches internally and never propagates to callers; the method instead returns an empty list. Exception tags should describe exceptions thrown to the caller." -->
public async Task<List<Display>> GetByCardConfigId(ObjectId configId)
{
try
@@ -307,6 +325,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// </summary>
/// <param name="displayConfigId">The ObjectId of the display configuration to check.</param>
/// <returns>The count of displays using the configuration.</returns>
/// <!-- aidoc:v1 sig=fddd490 body=6e359c3 -->
public async Task<long> IsDisplayConfigInUse(ObjectId displayConfigId)
{
return await Collection.CountDocumentsAsync(
@@ -324,6 +343,8 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// <param name="listPocObId">The new list of point of care ObjectIds.</param>
/// <returns>The updated Display if successful; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "Method catches all exceptions (catch (Exception e)) and returns null; no exception is actually thrown or propagated. The <exception cref=\"Exception\"> tag misleads readers into expecting the method to throw." -->
public async Task<Display?> UpdatePointOfCareList(ObjectId objectId, List<ObjectId> listPocObId)
{
try
@@ -349,6 +370,8 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// <param name="config">The new DisplayConfig to set.</param>
/// <returns>The updated Display if successful; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The catch block swallows all exceptions and returns null, so Exception is never propagated to the caller." -->
public async Task<Display?> UpdateConfig(ObjectId objectId, DisplayConfig config)
{
try
@@ -374,6 +397,8 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// <param name="displayConfigId">The new display configuration ObjectId to set.</param>
/// <returns>The updated Display if successful; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions internally and returns null; it never throws Exception, so documenting <exception cref=\"Exception\"> is misleading for callers." -->
public async Task<Display?> UpdateConfigId(ObjectId objectId, ObjectId displayConfigId)
{
try
@@ -399,6 +424,8 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// <param name="objectIdConfigDisplay">The ObjectId of the display configuration preset.</param>
/// <returns>The updated Display if successful; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "The method catches Exception internally and never rethrows it, so <exception cref=\"Exception\"> misleads callers into expecting the exception to propagate. The method always returns null on failure rather than throwing." -->
public async Task<Display?> UpdateConfigPreset(ObjectId objectIdDisplay, ObjectId objectIdConfigDisplay)
{
try
@@ -424,6 +451,7 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// <param name="name">The new name for the display.</param>
/// <returns>The updated Display if successful.</returns>
/// <exception cref="Exception">Throws an exception if MongoDB update fails.</exception>
/// <!-- aidoc:v1 sig=0662978 body=870f296 -->
public async Task<Display> UpdateName(Display display, string name)
{
try
@@ -453,6 +481,8 @@ public class DisplayRepository : MongoRepository<Display>, IDisplayRepository
/// <param name="unitId">The ObjectId of the unit whose displays should be deleted.</param>
/// <returns>True if deletion was successful; otherwise, false.</returns>
/// <exception cref="Exception">Logs errors and returns false on failure.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "The method catches all exceptions internally via `catch (Exception e)` and never propagates them to the caller; documenting `Exception` as a thrown exception is misleading" -->
public async Task<bool> DeleteManyByUnitId(ObjectId unitId)
{
try
@@ -14,6 +14,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repository implementation for managing HistoricalConfigChanges entities in MongoDB.
/// Provides CRUD operations and specialized queries for tracking configuration changes over time.
/// </summary>
/// <!-- aidoc:v1 sig=ac48934 -->
public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfigChanges>,
IHistoricalConfigChangesRepository
{
@@ -27,6 +28,7 @@ public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfi
/// <param name="database">The MongoDB database instance.</param>
/// <param name="logger">Logger for repository operations.</param>
/// <exception cref="ArgumentNullException">Thrown when apiSettings is null.</exception>
/// <!-- aidoc:v1 sig=4d362f8 body=a0d2d7c -->
public HistoricalConfigChangesRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database,
ILogger<HistoricalConfigChangesRepository> logger) : base(database)
{
@@ -39,6 +41,7 @@ public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfi
/// Gets the name of the collection for historical configuration changes.
/// </summary>
/// <returns>The collection name from API settings, or default "historicalConfigChanges".</returns>
/// <!-- aidoc:v1 sig=94e22ff body=211bf70 -->
public override string GetCollectionName()
{
return _apiSettings.HistoricalConfigChanges ?? "historicalConfigChanges";
@@ -50,6 +53,8 @@ public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfi
/// <param name="historicalConfigChanges">The HistoricalConfigChanges entity to insert.</param>
/// <returns>The inserted HistoricalConfigChanges with generated ID, or null if insertion fails.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "The <exception cref=\"Exception\"> tag implies the method throws Exception, but the catch block catches all exceptions internally and returns null; the method does not propagate any exceptions to the caller." -->
public override async Task<HistoricalConfigChanges?> InsertOneAsync(HistoricalConfigChanges historicalConfigChanges)
{
try
@@ -69,6 +74,7 @@ public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfi
/// </summary>
/// <param name="id">The ObjectId of the record to delete.</param>
/// <returns>The deleted HistoricalConfigChanges if found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=20dbcc3 body=040c92d -->
public async Task<HistoricalConfigChanges?> Delete(ObjectId id)
{
return await DeleteAsync(id);
@@ -78,6 +84,7 @@ public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfi
/// Retrieves all historical configuration change records.
/// </summary>
/// <returns>A collection of all HistoricalConfigChanges entities.</returns>
/// <!-- aidoc:v1 sig=d7a85d4 body=abac63b -->
public async Task<ICollection<HistoricalConfigChanges>> FindAll()
{
var result = await Collection.FindAsync(_ => true);
@@ -88,6 +95,7 @@ public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfi
/// Retrieves all IDs of historical configuration change records.
/// </summary>
/// <returns>A list of all ObjectIds in the collection.</returns>
/// <!-- aidoc:v1 sig=9552257 body=9650290 -->
public async Task<List<ObjectId>> FindAllIds()
{
List<ObjectId> listCollection = [];
@@ -103,6 +111,7 @@ public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfi
/// </summary>
/// <param name="id">The ObjectId of the record to retrieve.</param>
/// <returns>The HistoricalConfigChanges if found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=1f8f1f0 body=dbebfe0 -->
public async Task<HistoricalConfigChanges?> FindById(ObjectId id)
{
var result = await Collection.FindAsync(Builders<HistoricalConfigChanges>.Filter.Eq(x => x.Id, id));
@@ -114,6 +123,7 @@ public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfi
/// </summary>
/// <param name="historicalConfigChanges">The HistoricalConfigChanges with updated values.</param>
/// <returns>The updated HistoricalConfigChanges if successful; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=42cea8e body=6c26e7c -->
public async Task<HistoricalConfigChanges?> Update(HistoricalConfigChanges historicalConfigChanges)
{
var filter = Builders<HistoricalConfigChanges>.Filter.Eq("_id", historicalConfigChanges.Id);
@@ -136,6 +146,7 @@ public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfi
/// <param name="cfgType">The type of configuration to filter by.</param>
/// <param name="num">The maximum number of records to retrieve. Default is 10.</param>
/// <returns>A collection of the most recent HistoricalConfigChanges for the specified type.</returns>
/// <!-- aidoc:v1 sig=bc7ddf0 body=c5e6a70 -->
public async Task<ICollection<HistoricalConfigChanges>> FindLastHistoricalConfigChangesByType(
DisplayConfigEnums.ConfigTypes cfgType, int num = 10)
{
@@ -159,6 +170,7 @@ public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfi
/// <param name="cfgType">Optional configuration type to filter by. If null, all types are included.</param>
/// <param name="num">The maximum number of records to retrieve. Default is 10.</param>
/// <returns>A collection of the most recent HistoricalConfigChanges for the specified user.</returns>
/// <!-- aidoc:v1 sig=2ce032b body=646e240 -->
public async Task<ICollection<HistoricalConfigChanges>> FindLastHistoricalConfigChangesByUser(string user,
DisplayConfigEnums.ConfigTypes? cfgType = null, int num = 10)
{
@@ -181,6 +193,7 @@ public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfi
/// Creates compound indexes on (configType, time) and (username, time) for improved query performance.
/// </summary>
/// <exception cref="Exception">Throws an exception if index creation fails; logs error details before throwing.</exception>
/// <!-- aidoc:v1 sig=4955da2 body=f833046 -->
public override async Task CreateIndexes()
{
try
@@ -15,6 +15,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repository implementation for managing <see cref="LightBeacon"/> entities in MongoDB.
/// Provides CRUD operations and query capabilities specific to light beacons.
/// </summary>
/// <!-- aidoc:v1 sig=f6a410c -->
public class LightBeaconRepository : MongoRepository<LightBeacon>, ILightBeaconRepository
{
private readonly ApiSettings _apiSettings;
@@ -25,6 +26,7 @@ public class LightBeaconRepository : MongoRepository<LightBeacon>, ILightBeaconR
/// </summary>
/// <param name="database">The MongoDB database instance used to access the collection.</param>
/// <param name="apiSettings">The application API settings containing configuration values, including the collection name.</param>
/// <!-- aidoc:v1 sig=005180d body=12fddac -->
public LightBeaconRepository(IMongoDatabase database, IOptions<ApiSettings> apiSettings) : base(database)
{
_apiSettings = apiSettings.Value;
@@ -34,6 +36,7 @@ public class LightBeaconRepository : MongoRepository<LightBeacon>, ILightBeaconR
/// Gets the name of the MongoDB collection used to store light beacons.
/// </summary>
/// <returns>The collection name retrieved from the API settings.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=b7c9492 -->
public override string GetCollectionName()
{
return _apiSettings.LightBeacons;
@@ -44,6 +47,7 @@ public class LightBeaconRepository : MongoRepository<LightBeacon>, ILightBeaconR
/// </summary>
/// <param name="configurationRelayList">A list of <see cref="ObjectId"/> values representing the relay identifiers to filter by.</param>
/// <returns>A <see cref="List{LightBeacon}"/> containing the matching light beacons. Returns an empty list if no matches are found.</returns>
/// <!-- aidoc:v1 sig=c392d31 body=b387b94 -->
public List<LightBeacon> GetLightBeaconInList(List<ObjectId> configurationRelayList)
{
var filterBuilder = Builders<LightBeacon>.Filter;
@@ -62,6 +66,7 @@ public class LightBeaconRepository : MongoRepository<LightBeacon>, ILightBeaconR
/// A <see cref="Task{LightBeacon}"/> representing the asynchronous operation.
/// The task result contains the <see cref="LightBeacon"/> if found; otherwise, <see langword="null"/>.
/// </returns>
/// <!-- aidoc:v1 sig=0f2f926 body=1b42ab2 -->
public async Task<LightBeacon?> GetById(ObjectId relayId)
{
try
@@ -85,6 +90,7 @@ public class LightBeaconRepository : MongoRepository<LightBeacon>, ILightBeaconR
/// A <see cref="Task{LightBeacon}"/> representing the asynchronous operation.
/// The task result contains the <see cref="LightBeacon"/> if found; otherwise, <see langword="null"/>.
/// </returns>
/// <!-- aidoc:v1 sig=adf2a24 body=8e1d78c -->
public async Task<LightBeacon?> GetByName(string? requestRelayName)
{
var filterBuilder = Builders<LightBeacon>.Filter;
@@ -102,6 +108,8 @@ public class LightBeaconRepository : MongoRepository<LightBeacon>, ILightBeaconR
/// A <see cref="Task{LightBeacon}"/> representing the asynchronous operation.
/// The task result contains the inserted <see cref="LightBeacon"/> if successful; otherwise, <see langword="null"/> if the operation fails.
/// </returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_returns
/// "The cref in the <returns> tag references Task{LightBeacon}, but the method's actual return type is Task<LightBeacon?} (nullable). The descriptive text correctly mentions the null case, so the semantic meaning is preserved, but the type reference is inaccurate." -->
public async Task<LightBeacon?> InsertOneAsyncAndReturn(LightBeacon beacon)
{
try
@@ -125,6 +133,7 @@ public class LightBeaconRepository : MongoRepository<LightBeacon>, ILightBeaconR
/// An <see cref="IFindFluent{LightBeacon, LightBeacon}"/> instance that can be used to further refine and execute the query.
/// </returns>
/// <exception cref="BadRequestException">Thrown when the text filter exceeds 100 characters in length.</exception>
/// <!-- aidoc:v1 sig=07ed538 body=4c87ab2 -->
public IFindFluent<LightBeacon, LightBeacon> GetPaginatedRelays(PaginationFilter filter)
{
var filterBuilder = Builders<LightBeacon>.Filter;
@@ -163,6 +172,7 @@ public class LightBeaconRepository : MongoRepository<LightBeacon>, ILightBeaconR
/// containing a list of matching <see cref="LightBeacon"/> objects.
/// </returns>
/// <exception cref="NotImplementedException">This method is not yet implemented.</exception>
/// <!-- aidoc:v1 sig=7342f3e body=bfa6f2f -->
public Task<List<LightBeacon>> GetSearchByName(string textToSearch)
{
throw new NotImplementedException();
@@ -175,6 +185,7 @@ public class LightBeaconRepository : MongoRepository<LightBeacon>, ILightBeaconR
/// <param name="filters">A list of <see cref="FilterDefinition{LightBeacon}"/> to be combined into the query.</param>
/// <param name="sort">The <see cref="SortDefinition{LightBeacon}"/> defining the sort order of the results.</param>
/// <returns>An <see cref="IFindFluent{LightBeacon, LightBeacon}"/> instance representing the constructed query.</returns>
/// <!-- aidoc:v1 sig=1b1403f body=e71d1c5 -->
private IFindFluent<LightBeacon, LightBeacon> CreateFindFluent(List<FilterDefinition<LightBeacon>> filters, SortDefinition<LightBeacon> sort)
{
var combinedFilter = filters.Any()
@@ -20,6 +20,7 @@ namespace adas_core.Infrastructure.Repositories;
/// options lists, diagnoses, allergies, procedures, treatments, and other reference data.
/// </summary>
/// <typeparam name="T">The type of MasterList entity to manage.</typeparam>
/// <!-- aidoc:v1 sig=f958de2 -->
public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository<T> where T : MasterList
{
private readonly ApiSettings _apiSettings;
@@ -30,6 +31,7 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="apiSettings">API settings containing collection names configuration.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <exception cref="ArgumentNullException">Thrown when apiSettings is null.</exception>
/// <!-- aidoc:v1 sig=800d538 body=d2b18a3 -->
public MasterListRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
{
if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
@@ -41,6 +43,7 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// Maps different MasterList subtypes to their corresponding MongoDB collection names.
/// </summary>
/// <returns>The collection name for the current MasterList type.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=64e6c55 -->
public override string GetCollectionName()
{
return typeof(T) switch
@@ -76,6 +79,7 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// </summary>
/// <param name="entity">The entity to insert.</param>
/// <exception cref="Exception">Throws and re-throws exceptions after logging.</exception>
/// <!-- aidoc:v1 sig=c7a7ad8 body=26b3581 -->
public override async Task InsertOneAsync(T entity)
{
try
@@ -94,6 +98,7 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// </summary>
/// <param name="id">The ObjectId of the entity to delete.</param>
/// <exception cref="Exception">Throws and re-throws exceptions after logging.</exception>
/// <!-- aidoc:v1 sig=3de1ad6 body=fe0ba8c -->
public async Task Delete(ObjectId id)
{
try
@@ -113,6 +118,7 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// </summary>
/// <param name="entity">The entity with updated values.</param>
/// <exception cref="Exception">Throws and re-throws exceptions after logging.</exception>
/// <!-- aidoc:v1 sig=019b691 body=863650a -->
public async Task Update(T entity)
{
try
@@ -133,6 +139,7 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="id">The ObjectId of the master list.</param>
/// <param name="newOpt">The OptionList with updated values.</param>
/// <returns>The updated OptionList if found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=64ca4dd body=a7714e6 -->
public async Task<OptionList?> UpdateFullMasterListOption(ObjectId id, OptionList newOpt)
{
var filter = Builders<T>.Filter.Where(o => o.Id == id && o.Options.Any(opt => opt.Id == newOpt.Id)
@@ -166,6 +173,12 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="id">The ObjectId of the entity to retrieve.</param>
/// <returns>The MasterList entity if found; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "Documents 'MasterList entity' but the method returns the generic type T? (Task<T?>)." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "Documents <exception cref='Exception'> but the method catches and handles all Exception internally, returning null; it does not rethrow." -->
/// <!-- aidoc-review:v1 severity=high kind=stale_summary
/// "Summary refers specifically to a 'master list entity' though the method is generic (Task<T?>) and not bound to a MasterList type." -->
public async Task<T?> FindById(ObjectId id)
{
try
@@ -197,6 +210,7 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="locale">The locale for translation.</param>
/// <returns>The OptionList with translated fields if found; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc:v1 sig=fdb2628 body=0e4983e -->
public async Task<OptionList?> FindOptionItemById(ObjectId masterId, ObjectId optionId, LocaleEnum locale)
{
try
@@ -342,6 +356,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="optionId">The ObjectId of the option to retrieve.</param>
/// <returns>The OptionList if found; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "The method catches Exception and returns null; it never propagates any exception, so documenting it with <exception cref=\"Exception\"> is misleading." -->
public async Task<OptionList?> FindOptionItemById(ObjectId masterId, ObjectId optionId)
{
try
@@ -374,6 +390,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="locale">Optional locale for translated option names.</param>
/// <returns>The MasterList entity with translated options if found; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "The method catches Exception internally and returns null; it does not propagate Exception to the caller, so the <exception cref=\"Exception\"/> tag is misleading." -->
public async Task<T?> FindById(ObjectId id, LocaleEnum? locale)
{
try
@@ -556,6 +574,14 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="name">The name of the master list to retrieve.</param>
/// <returns>The MasterList entity if found; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=high kind=stale_summary
/// "Summary says 'master list entity' but the method is generic (FindByName<T>) and is not specific to master lists." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "Returns tag says 'The MasterList entity if found; otherwise, null' but the method returns Task<T?>, a generic nullable type, not specifically a MasterList." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_param_role
/// "Param description refers to 'the master list to retrieve', but the entity type is the generic T, not specifically MasterList." -->
/// <!-- aidoc-review:v1 severity=high kind=extra_exception
/// "Documents <exception cref='Exception'> but the method catches all Exception instances and never propagates them to the caller." -->
public async Task<T?> FindByName(string name)
{
try
@@ -584,6 +610,7 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="id">The ObjectId of the master list.</param>
/// <param name="textSearch">Optional text to search within options.</param>
/// <returns>A list of matching OptionList items.</returns>
/// <!-- aidoc:v1 sig=569d223 body=bb7f2c6 -->
public async Task<List<OptionList>> GetMasterListByIdAndTextSearchContaining(ObjectId id, string? textSearch)
{
return await GetOptionsByTextSearch(textSearch, id);
@@ -594,6 +621,7 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// </summary>
/// <param name="filter">The pagination and filtering parameters.</param>
/// <returns>A fluent queryable for MasterList results.</returns>
/// <!-- aidoc:v1 sig=bbb39c7 body=f42ebaa -->
public IFindFluent<T, T> GetPaginatedMasterList(PaginationFilter filter)
{
var filterBuilder = Builders<T>.Filter;
@@ -621,6 +649,10 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="filter">The pagination and filtering parameters.</param>
/// <param name="listId">The ObjectId of the master list.</param>
/// <returns>A list of filtered OptionList items.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Summary claims pagination is performed, but the code only applies an optional text filter and returns all matching options with no Skip/Take/page logic." -->
/// <!-- aidoc-review:v1 severity=high kind=mentions_removed_behavior
/// "Documentation describes pagination via the filter, but no pagination is applied; only FilteredRequest.Text is consumed." -->
public async Task<List<OptionList>> GetPaginatedOptions(PaginationFilter filter, ObjectId listId)
{
//TODO: LOCALE
@@ -646,6 +678,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="opt">The option element to add.</param>
/// <returns>The newly created OptionList if successful; otherwise, null if duplicate exists.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=high kind=extra_exception
/// "The method catches Exception internally and returns null; it never propagates an Exception to the caller, so the <exception> tag is incorrect." -->
public async Task<OptionList?> AddOptionToMasterList(ObjectId id, FilterOptionListElement opt)
{
var exist = await GetMasterListByIdAndSearchOptions(id, opt);
@@ -689,6 +723,10 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// </summary>
/// <returns>An enumerable of all MasterList entities.</returns>
/// <exception cref="Exception">Logs errors and returns empty list on failure.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "Documentation states the method returns 'MasterList entities', but the method is generic and returns IEnumerable<T>." -->
/// <!-- aidoc-review:v1 severity=high kind=stale_summary
/// "Summary describes retrieving 'all master list entities', but the method is a generic GetAll<T>() that retrieves all entities of the type parameter T." -->
public async Task<IEnumerable<T>> GetAll()
{
try
@@ -708,6 +746,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// </summary>
/// <returns>An enumerable of MasterListDto containing id, name, description, listType, and options count.</returns>
/// <exception cref="Exception">Logs errors and returns empty list on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "Method catches all Exception instances and returns an empty list; it does not throw Exception to the caller, so <exception cref=\"Exception\"> is misleading." -->
public async Task<IEnumerable<MasterListDto>> GetAllWithoutOptions()
{
try
@@ -736,6 +776,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// </summary>
/// <returns>The total count of entities.</returns>
/// <exception cref="Exception">Logs errors and returns 0 on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions internally and returns 0, so it never throws Exception to the caller. The <exception> tag with description 'Logs errors and returns 0 on failure' describes catch-block behavior rather than a thrown exception." -->
public async Task<int> Count()
{
try
@@ -758,6 +800,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="filters">The filter criteria including text, name, description, and optionType.</param>
/// <returns>A list of matching OptionList items ordered by name.</returns>
/// <exception cref="Exception">Logs errors and returns empty list on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions internally and returns an empty list, so it never throws Exception to the caller; documenting <exception cref=\"Exception\"> is misleading." -->
public async Task<List<OptionList>> GetMasterListByIdAndSearchOptions(ObjectId id, FilterOptionListElement? filters)
{
try
@@ -973,6 +1017,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="locale">The locale for translation updates.</param>
/// <returns>The updated OptionList if successful; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all Exception types internally and returns null; it does not throw Exception to the caller, so declaring <exception cref=\"Exception\"> is misleading." -->
public async Task<OptionList?> UpdateMasterListOption(ObjectId id, OptionList newOpt, LocaleEnum locale)
{
// 1. Evitar duplicados
@@ -1073,6 +1119,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="newOpt">The OptionList with updated values.</param>
/// <returns>The updated OptionList if successful; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions internally in a try/catch and returns null; it never propagates an Exception to the caller, so documenting <exception cref='Exception'> is misleading." -->
public async Task<OptionList?> UpdateMasterListOption(ObjectId id, OptionList newOpt)
{
var master = await FindById(id);
@@ -1108,6 +1156,7 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="id">The ObjectId of the master list.</param>
/// <param name="deleteOptId">The ObjectId of the option to delete.</param>
/// <returns>True if the option was deleted; otherwise, false.</returns>
/// <!-- aidoc:v1 sig=e663f16 body=75627bc -->
public async Task<bool> DeleteMasterListOption(ObjectId id, ObjectId deleteOptId)
{
// Define el filtro para encontrar el documento por su _id
@@ -1132,6 +1181,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="opt">The UpdateMasterListDetailsDto with updated values.</param>
/// <returns>The updated UpdateMasterListDetailsDto if successful; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "The method catches all exceptions internally and returns null; it never propagates an exception to the caller, so the <exception cref=\"Exception\"> tag is misleading." -->
public async Task<UpdateMasterListDetailsDto?> UpdateOptionDetailsToMasterList(ObjectId id,
UpdateMasterListDetailsDto opt)
{
@@ -1167,6 +1218,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="name">The new name.</param>
/// <returns>True if the update was successful; otherwise, false.</returns>
/// <exception cref="Exception">Logs errors and returns false on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all Exception types internally and never propagates them to the caller; documenting <exception cref=\"Exception\"> implies callers must handle it, which is misleading." -->
public async Task<bool> UpdateMasterListName(ObjectId id, string name)
{
var filter = Builders<T>.Filter.And(
@@ -1193,6 +1246,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="description">The new description.</param>
/// <returns>True if the update was successful; otherwise, false.</returns>
/// <exception cref="Exception">Logs errors and returns false on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions and returns false; it never propagates an exception to the caller, so the <exception cref=\"Exception\"/> tag is incorrect." -->
public async Task<bool> UpdateMasterListDescription(ObjectId id, string description)
{
var filter = Builders<T>.Filter.And(
@@ -1219,6 +1274,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="oldOpt">The OptionList to remove.</param>
/// <returns>True if the option was removed; otherwise, false.</returns>
/// <exception cref="Exception">Logs errors and returns false on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_exception
/// "<exception cref=\"Exception\"> documents an exception that the method never throws; all exceptions are caught internally and the method returns false." -->
public async Task<bool> RemoveMasterListOption(ObjectId id, OptionList oldOpt)
{
var filter = Builders<T>.Filter.Eq("_id", id);
@@ -1250,6 +1307,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// Creates necessary indexes for the MasterList collection.
/// Currently creates text indexes for DiagnosisList on options.name, options.description, and options._id.
/// </summary>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Documentation claims the method creates 'text indexes', but the code uses IndexKeys.Ascending(...) to create standard ascending (non-text) indexes." -->
public override async Task CreateIndexes()
{
if (typeof(T) == typeof(DiagnosisList))
@@ -1275,6 +1334,7 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// </summary>
/// <param name="textSearch">Optional text to search within options.</param>
/// <returns>A list of matching OptionList items.</returns>
/// <!-- aidoc:v1 sig=484b092 body=48e3496 -->
public async Task<List<OptionList>> GetMasterListByTextSearch(string? textSearch)
{
return await GetOptionsByTextSearch(textSearch);
@@ -1287,6 +1347,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="id">Optional master list ObjectId to filter results.</param>
/// <returns>A list of matching OptionList items ordered by name.</returns>
/// <exception cref="Exception">Logs errors and returns empty list on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions internally via a broad try/catch and returns an empty list; it never rethrows, so the <exception cref=\"Exception\"> tag documents behavior that does not propagate to the caller." -->
private async Task<List<OptionList>> GetOptionsByTextSearch(string? textSearch, ObjectId? id = null)
{
try
@@ -1364,6 +1426,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="filters">List of filter definitions to apply.</param>
/// <param name="sort">Sort definition for the query results.</param>
/// <returns>A fluent queryable for T results.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Summary describes the method as creating a fluent query 'for paginated results', but the method body performs no pagination (no Skip/Limit); it only builds a find query with filters and sort." -->
private IFindFluent<T, T> CreateFindFluent(List<FilterDefinition<T>> filters, SortDefinition<T> sort)
{
var combinedFilter = filters.Any()
@@ -1379,6 +1443,10 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="localeList">The default locale to exclude from translations.</param>
/// <param name="opt">The option name to use as default translation.</param>
/// <returns>A Locale object with translations for all other locales.</returns>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_param_role
/// "localeList is documented as 'The default locale to exclude' but it is not necessarily the default; the code separately skips LocaleEnum.Default and localeList is just another locale to exclude." -->
/// <!-- aidoc-review:v1 severity=medium kind=stale_summary
/// "Summary states the method operates 'based on a default locale' and excludes only 'the specified default', but the code creates identical LocaleItems for every locale except both LocaleEnum.Default and localeList, with no use of any default locale as a basis." -->
private Locale GetNewItemLocale(LocaleEnum localeList, string opt)
{
var newLocale = new Locale();
@@ -1418,6 +1486,7 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// </summary>
/// <param name="input">The input string to build the pattern from.</param>
/// <returns>A regex-compatible pattern string.</returns>
/// <!-- aidoc:v1 sig=2992c00 body=ae88daf -->
private static string BuildRegexPattern(string input)
{
var regexPattern = new StringBuilder();
@@ -1459,6 +1528,8 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
/// <param name="locale">The locale for translation.</param>
/// <returns>A list of matching OptionList items ordered by name.</returns>
/// <exception cref="Exception">Logs errors and returns empty list on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches Exception internally and does not throw it to the caller; the <exception cref=\"Exception\"> tag is misleading because it implies the exception propagates." -->
private async Task<List<OptionList>> GetMasterListByIdAndTextSearch(
ObjectId id, string newOptName, LocaleEnum locale)
{
@@ -13,6 +13,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repository implementation for managing <see cref="Medicine"/> entities in MongoDB.
/// Provides CRUD operations, search, pagination, and aggregation capabilities specific to medicines.
/// </summary>
/// <!-- aidoc:v1 sig=16673ad -->
public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
{
private readonly ApiSettings _apiSettings;
@@ -23,6 +24,7 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// <param name="apiSettings">The application API settings containing configuration values, including the collection name. Cannot be <see langword="null"/>.</param>
/// <param name="database">The MongoDB database instance used to access the collection.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="apiSettings"/> is <see langword="null"/>.</exception>
/// <!-- aidoc:v1 sig=78d0590 body=d2b18a3 -->
public MedicineRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
{
if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
@@ -36,6 +38,7 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// Falls back to the default "medicines" collection name when not configured in the API settings.
/// </summary>
/// <returns>The collection name retrieved from the API settings, or "medicines" if not configured.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=24e9d1c -->
public override string GetCollectionName()
{
return _apiSettings.Medicines ?? "medicines";
@@ -49,6 +52,7 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// A <see cref="Task{Medicine}"/> representing the asynchronous operation.
/// The task result contains the first <see cref="Medicine"/> matching the criteria, or <see langword="null"/> if no match is found.
/// </returns>
/// <!-- aidoc:v1 sig=b6d43c1 body=db3587a -->
public async Task<Medicine?> GetMedicine(string code)
{
var result = await Collection.FindAsync(x => x.Codes.Contains(code) || x.Notes.Contains(code));
@@ -65,6 +69,7 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// A <see cref="Task{List{Medicine}}"/> representing the asynchronous operation.
/// The task result contains a list of matching <see cref="Medicine"/> objects. Returns an empty list if no matches are found.
/// </returns>
/// <!-- aidoc:v1 sig=68faf9f body=85d920f -->
public async Task<List<Medicine>> GetMedicineByCodeOrNote(List<string> codeNotes)
{
var filter = Builders<Medicine>.Filter.AnyIn("Codes", codeNotes.ToArray());
@@ -81,6 +86,7 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// A <see cref="Task{Medicine}"/> representing the asynchronous operation.
/// The task result contains the <see cref="Medicine"/> if found; otherwise, <see langword="null"/>.
/// </returns>
/// <!-- aidoc:v1 sig=84930f7 body=2ce8f8c -->
public async Task<Medicine?> GetMedicineByName(string name)
{
var filter = Builders<Medicine>.Filter.Eq(p => p.Name, name);
@@ -96,6 +102,7 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// A <see cref="Task{List{Medicine}}"/> representing the asynchronous operation.
/// The task result contains a list of all <see cref="Medicine"/> objects. Returns an empty list if the collection is empty.
/// </returns>
/// <!-- aidoc:v1 sig=6bce187 body=bdbdf96 -->
public async Task<List<Medicine>> GetAll()
{
var result = await Collection.FindAsync(_ => true);
@@ -111,6 +118,8 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// A <see cref="Task{Medicine}"/> representing the asynchronous operation.
/// The task result contains the <see cref="Medicine"/> if found; otherwise, <see langword="null"/>.
/// </returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_returns
/// "The cref uses Task{Medicine} but the method's actual return type is Task<Medicine?>; however, the explanatory sentence correctly describes the nullable behavior." -->
public async Task<Medicine?> GetMedicineById(ObjectId medicineId)
{
var filter = Builders<Medicine>.Filter.Eq(p => p.Id, medicineId);
@@ -127,6 +136,8 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// A <see cref="Task{Medicine}"/> representing the asynchronous operation.
/// The task result contains the newly inserted <see cref="Medicine"/> retrieved by its name, or <see langword="null"/> if the lookup fails.
/// </returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_returns
/// "The return type is Task<Medicine?> (nullable), but the cref uses Task{Medicine} which represents the non-nullable Task<Medicine>. The prose does mention null, so meaning is preserved." -->
public async Task<Medicine?> PostMedicine(Medicine medicine)
{
await Collection.InsertOneAsync(medicine);
@@ -143,6 +154,7 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// A <see cref="Task{Medicine}"/> representing the asynchronous operation.
/// The task result contains the same <see cref="Medicine"/> instance that was passed in, after the update operation has been issued.
/// </returns>
/// <!-- aidoc:v1 sig=baa8582 body=be3411f -->
public async Task<Medicine?> UpdateMedicine(Medicine medicine)
{
await UpdateOneAsync(medicine.Id, medicine);
@@ -155,6 +167,7 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// </summary>
/// <param name="medicineId">The <see cref="ObjectId"/> of the medicine to delete.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous delete operation.</returns>
/// <!-- aidoc:v1 sig=ea3ac00 body=5d15af8 -->
public async Task DeleteMedicineById(ObjectId medicineId)
{
var filter = Builders<Medicine>.Filter.Eq(po => po.Id, medicineId);
@@ -172,6 +185,7 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// An <see cref="IFindFluent{Medicine, Medicine}"/> instance that can be used to further refine and execute the query.
/// When no filters are provided, all medicines are returned sorted by name.
/// </returns>
/// <!-- aidoc:v1 sig=067ab87 body=1dc1cf3 -->
public IFindFluent<Medicine, Medicine> GetPaginatedMedicines(PaginationFilter filter)
{
// Crear variable con la clase que construye los filtros que necesitamos
@@ -220,6 +234,7 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// An <see cref="IAggregateFluent{BsonDocument}"/> representing the aggregation pipeline that, when executed,
/// yields documents containing the distinct values of the specified field.
/// </returns>
/// <!-- aidoc:v1 sig=3fad0c3 body=ba53337 -->
public IAggregateFluent<BsonDocument> GetDistinctFieldDataQuery(string field)
{
return Collection.Aggregate()
@@ -238,6 +253,7 @@ public class MedicineRepository : MongoRepository<Medicine>, IMedicineRepository
/// containing a list of distinct group names as strings.
/// </returns>
/// <exception cref="NotImplementedException">This method is not yet implemented.</exception>
/// <!-- aidoc:v1 sig=4759c2c body=bfa6f2f -->
public Task<List<string>> GetAllGroups()
{
throw new NotImplementedException();
@@ -15,6 +15,7 @@ namespace adas_core.Infrastructure.Repositories;
/// to customize schema setup, seeding, and insertion behavior.
/// </summary>
/// <typeparam name="T">The domain model type persisted in the MongoDB collection.</typeparam>
/// <!-- aidoc:v1 sig=69998d5 -->
public abstract class MongoRepository<T> : IMongoRepository<T>
{
/// <summary>
@@ -33,6 +34,7 @@ public abstract class MongoRepository<T> : IMongoRepository<T>
/// Initializes a new instance of the <see cref="MongoRepository{T}"/> class using the provided database.
/// </summary>
/// <param name="database">The MongoDB database instance used to access collections. Must not be <see langword="null"/>.</param>
/// <!-- aidoc:v1 sig=d790eeb body=2671b37 -->
protected MongoRepository(IMongoDatabase database)
{
Db = database;
@@ -42,6 +44,7 @@ public abstract class MongoRepository<T> : IMongoRepository<T>
/// When implemented in a derived class, returns the name of the MongoDB collection used to store documents of type <typeparamref name="T"/>.
/// </summary>
/// <returns>The MongoDB collection name as a string.</returns>
/// <!-- aidoc:v1 sig=e2b0ea0 -->
public abstract string GetCollectionName();
/// <summary>
@@ -73,6 +76,7 @@ public abstract class MongoRepository<T> : IMongoRepository<T>
/// </summary>
/// <param name="obj">The document of type <typeparamref name="T"/> to insert.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous insert operation.</returns>
/// <!-- aidoc:v1 sig=7489d1f body=3bc7781 -->
public virtual async Task InsertOneAsync(T obj)
{
try
@@ -93,6 +97,7 @@ public abstract class MongoRepository<T> : IMongoRepository<T>
/// <param name="id">The <see cref="ObjectId"/> value of the document's <c>_id</c> field.</param>
/// <param name="obj">The replacement document of type <typeparamref name="T"/>.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous replace/upsert operation.</returns>
/// <!-- aidoc:v1 sig=e9b79ac body=34c3c0c -->
public async Task UpdateOneAsync(ObjectId id, T obj)
{
try
@@ -117,6 +122,7 @@ public abstract class MongoRepository<T> : IMongoRepository<T>
/// A <see cref="Task{T}"/> representing the asynchronous operation.
/// The task result contains the deleted document, or <see langword="null"/> / default if no document matched or an error occurred.
/// </returns>
/// <!-- aidoc:v1 sig=de6ed30 body=36e5c1c -->
public async Task<T?> DeleteAsync(ObjectId id)
{
try
@@ -136,6 +142,7 @@ public abstract class MongoRepository<T> : IMongoRepository<T>
/// derived classes should override this method to define their own indexes.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous index creation operation.</returns>
/// <!-- aidoc:v1 sig=f76a2b3 body=6805ef5 -->
public virtual Task CreateIndexes()
{
return Task.CompletedTask;
@@ -146,6 +153,7 @@ public abstract class MongoRepository<T> : IMongoRepository<T>
/// derived classes should override this method to provide custom seeding logic.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous seeding operation.</returns>
/// <!-- aidoc:v1 sig=e4d5f7d body=6805ef5 -->
public virtual Task InsertInitialLoad()
{
return Task.CompletedTask;
@@ -157,6 +165,7 @@ public abstract class MongoRepository<T> : IMongoRepository<T>
/// </summary>
/// <param name="obj">The list of documents of type <typeparamref name="T"/> to insert.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous bulk insert operation.</returns>
/// <!-- aidoc:v1 sig=f63f7ad body=4633ba9 -->
public virtual async Task InsertManyAsync(List<T> obj)
{
try
@@ -178,6 +187,7 @@ public abstract class MongoRepository<T> : IMongoRepository<T>
/// <param name="id">The new <see cref="ObjectId"/> value to assign.</param>
/// <param name="oldId">The existing <see cref="ObjectId"/> value to replace.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous update operation.</returns>
/// <!-- aidoc:v1 sig=2f5f8d3 body=af391c3 -->
protected async Task UpdateManyObjectIdAsync(string nameId, ObjectId id, ObjectId oldId)
{
try
@@ -202,6 +212,7 @@ public abstract class MongoRepository<T> : IMongoRepository<T>
/// A <see cref="Task{T}"/> representing the asynchronous operation.
/// The task result contains the deleted document, or <see langword="null"/> / default if no document matched or an error occurred.
/// </returns>
/// <!-- aidoc:v1 sig=ec974d1 body=36e5c1c -->
protected async Task<T?> DeleteAsync(string id)
{
try
@@ -225,6 +236,7 @@ public abstract class MongoRepository<T> : IMongoRepository<T>
/// <see langword="true"/> if a collection with the given name exists; otherwise, <see langword="false"/>.
/// Returns <see langword="false"/> when an exception is thrown while querying the database.
/// </returns>
/// <!-- aidoc:v1 sig=bc8012c body=ec4a9e5 -->
protected bool CollectionExists(string collectionName)
{
try
@@ -13,6 +13,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repository implementation for managing Notice entities in MongoDB.
/// Provides CRUD operations for notices/notifications that can be displayed on screens.
/// </summary>
/// <!-- aidoc:v1 sig=a7dc3b2 -->
public class NoticeRepository : MongoRepository<Notice>, INoticeRepository
{
private readonly ApiSettings _apiSettings;
@@ -23,6 +24,7 @@ public class NoticeRepository : MongoRepository<Notice>, INoticeRepository
/// <param name="apiSettings">API settings containing collection names configuration.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <exception cref="ArgumentNullException">Thrown when apiSettings is null.</exception>
/// <!-- aidoc:v1 sig=c18eb8b body=99d85d9 -->
public NoticeRepository(IOptions<ApiSettings>? apiSettings, IMongoDatabase database) : base(database)
{
if (apiSettings != null)
@@ -35,6 +37,7 @@ public class NoticeRepository : MongoRepository<Notice>, INoticeRepository
/// Gets the name of the collection for notices.
/// </summary>
/// <returns>The collection name from API settings.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=dfe078b -->
public override string GetCollectionName()
{
return _apiSettings.Notices;
@@ -46,6 +49,8 @@ public class NoticeRepository : MongoRepository<Notice>, INoticeRepository
/// </summary>
/// <param name="notice">The Notice entity to insert.</param>
/// <exception cref="Exception">Logs warning and silently fails on insertion error.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches Exception and does not re-throw it, so documenting <exception cref=\"Exception\"> is misleading—callers will not see this exception propagate." -->
public override async Task InsertOneAsync(Notice notice)
{
try
@@ -64,6 +69,7 @@ public class NoticeRepository : MongoRepository<Notice>, INoticeRepository
/// </summary>
/// <param name="id">The ObjectId of the notice to delete.</param>
/// <exception cref="Exception">Throws and re-throws exceptions after logging.</exception>
/// <!-- aidoc:v1 sig=3de1ad6 body=c1d807b -->
public async Task Delete(ObjectId id)
{
try
@@ -83,6 +89,7 @@ public class NoticeRepository : MongoRepository<Notice>, INoticeRepository
/// </summary>
/// <param name="notice">The Notice entity with updated values.</param>
/// <exception cref="Exception">Throws and re-throws exceptions after logging.</exception>
/// <!-- aidoc:v1 sig=64f77d8 body=b33b6f7 -->
public async Task Update(Notice notice)
{
try
@@ -101,6 +108,8 @@ public class NoticeRepository : MongoRepository<Notice>, INoticeRepository
/// </summary>
/// <returns>An enumerable of all Notice entities.</returns>
/// <exception cref="Exception">Logs errors and returns empty list on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches and handles all exceptions internally (returns empty list), so no exception is propagated to the caller; documenting <exception cref=\"Exception\"> is misleading." -->
public async Task<IEnumerable<Notice>> FindAll()
{
try
@@ -121,6 +130,8 @@ public class NoticeRepository : MongoRepository<Notice>, INoticeRepository
/// <param name="id">The ObjectId of the notice to retrieve.</param>
/// <returns>The Notice if found; otherwise, null.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method's try-catch handles all exceptions internally and returns null, so no exception is ever propagated to the caller; documenting <exception cref=\"Exception\"> is misleading." -->
public async Task<Notice?> FindById(ObjectId id)
{
try
@@ -143,6 +154,8 @@ public class NoticeRepository : MongoRepository<Notice>, INoticeRepository
/// <param name="date">The date to filter notices by.</param>
/// <returns>An enumerable of Notice entities matching the date, or null on error.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The <exception cref=\"Exception\"> tag documents an exception that is never thrown to callers; the catch block handles all exceptions internally and returns null instead." -->
public async Task<IEnumerable<Notice>?> FindByDate(DateTime date)
{
try
@@ -165,6 +178,7 @@ public class NoticeRepository : MongoRepository<Notice>, INoticeRepository
/// <param name="type">The notice type to filter by.</param>
/// <returns>An enumerable of Notice entities matching the type, or null on error.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc:v1 sig=c8e3fb2 body=d0629e2 -->
public async Task<IEnumerable<Notice>?> FindByType(string type)
{
try
@@ -187,6 +201,7 @@ public class NoticeRepository : MongoRepository<Notice>, INoticeRepository
/// <param name="displayId">The ObjectId of the display to filter by.</param>
/// <returns>An enumerable of Notice entities for the display, or null on error.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception>
/// <!-- aidoc:v1 sig=a6848c6 body=c64a895 -->
public async Task<IEnumerable<Notice>?> FindByDisplayId(ObjectId displayId)
{
try
@@ -207,6 +222,8 @@ public class NoticeRepository : MongoRepository<Notice>, INoticeRepository
/// Creates the necessary indexes for the Notice collection.
/// Creates compound indexes on (noticeType, noticeDate) and (noticeDate) for improved query performance.
/// </summary>
/// <!-- aidoc-review:v1 severity=low kind=wrong_summary
/// "Documentation states 'compound indexes' (plural), but only (noticeType, noticeDate) is compound; (noticeDate) is a single-field index." -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions { Background = true, Unique = false };
@@ -13,6 +13,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repository implementation for managing PatientObservation archive entities in MongoDB.
/// Provides operations for storing and retrieving historical patient observations.
/// </summary>
/// <!-- aidoc:v1 sig=208c7de -->
public class ObservationArchiveRepository : MongoRepository<PatientObservation>, IObservationArchiveRepository
{
private readonly ApiSettings _apiSettings;
@@ -23,6 +24,7 @@ public class ObservationArchiveRepository : MongoRepository<PatientObservation>,
/// <param name="apiSettings">API settings containing collection names configuration.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <exception cref="ArgumentNullException">Thrown when apiSettings is null.</exception>
/// <!-- aidoc:v1 sig=fa9b83d body=d2b18a3 -->
public ObservationArchiveRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
{
if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
@@ -38,6 +40,8 @@ public class ObservationArchiveRepository : MongoRepository<PatientObservation>,
/// <param name="lastDate">The cutoff date to filter observations (inclusive).</param>
/// <param name="filterObservations">Optional list of observation names to filter by. If null, retrieves all distinct observations.</param>
/// <returns>A list of PatientObservation entities sorted by time descending.</returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_returns
/// "The returned list is sorted by time descending only within each observation name group (each foreach iteration), not globally across all observation types, since results are appended via AddRange without re-sorting." -->
public async Task<List<PatientObservation>> AggregatedPatientLastObservations(ObjectId patientId, int num,
DateTime lastDate, List<string>? filterObservations = null)
{
@@ -64,6 +68,7 @@ public class ObservationArchiveRepository : MongoRepository<PatientObservation>,
/// Gets the name of the collection for archived patient observations.
/// </summary>
/// <returns>The collection name from API settings, or default "archive_patients_observations".</returns>
/// <!-- aidoc:v1 sig=94e22ff body=81daff1 -->
public override string GetCollectionName()
{
return _apiSettings.ArchivePatientsObservations ?? "archive_patients_observations";
@@ -76,6 +81,7 @@ public class ObservationArchiveRepository : MongoRepository<PatientObservation>,
/// <param name="patientObservation">The PatientObservation entity to insert.</param>
/// <exception cref="MongoWriteException">Throws when duplicate key error persists after max retries.</exception>
/// <exception cref="Exception">Throws when insertion fails for reasons other than duplicate key.</exception>
/// <!-- aidoc:v1 sig=ae8c780 body=b4e7347 -->
public new async Task InsertOneAsync(PatientObservation patientObservation)
{
const int maxRetries = 2; // Número máximo de reintentos
@@ -117,6 +123,8 @@ public class ObservationArchiveRepository : MongoRepository<PatientObservation>,
/// </summary>
/// <param name="date">The cutoff date. Observations older than this date will be deleted.</param>
/// <returns>The number of deleted documents.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "Method returns Task, not Task<int>; the number of deleted documents is not exposed to callers." -->
public async Task DeleteBeforeDate(DateTime date)
{
var filter = Builders<PatientObservation>.Filter.Lt(po => po.Time, date);
@@ -128,6 +136,7 @@ public class ObservationArchiveRepository : MongoRepository<PatientObservation>,
/// </summary>
/// <param name="observations">An enumerable of PatientObservation entities to insert.</param>
/// <returns>The count of successfully inserted documents.</returns>
/// <!-- aidoc:v1 sig=f522e46 body=daebb76 -->
public async Task<long> InsertBatch(IEnumerable<PatientObservation> observations)
{
var writes = new List<WriteModel<PatientObservation>>();
@@ -143,6 +152,8 @@ public class ObservationArchiveRepository : MongoRepository<PatientObservation>,
/// </summary>
/// <param name="patientId">The ObjectId of the patient.</param>
/// <returns>A list of all PatientObservation entities for the patient.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Summary states observations are 'archived', but the code only filters by PatientId with no archive-status filter, implying retrieval behavior the code does not perform." -->
public async Task<List<PatientObservation>> FindAllFromPatient(ObjectId patientId)
{
var filter = Builders<PatientObservation>.Filter.Eq(p => p.PatientId, patientId);
@@ -158,6 +169,7 @@ public class ObservationArchiveRepository : MongoRepository<PatientObservation>,
/// <param name="patientId">The ObjectId of the patient.</param>
/// <param name="filterObservations">Optional pre-filtered list of observation names. If null or empty, computes distinct values.</param>
/// <returns>A list of distinct observation name strings.</returns>
/// <!-- aidoc:v1 sig=b7f7b8f body=198b120 -->
private async Task<List<string>> AggregatePatientObservations(ObjectId patientId,
List<string>? filterObservations = null)
{
@@ -21,6 +21,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repository implementation for managing <see cref="PatientObservation"/> entities in MongoDB.
/// Provides specialized query, aggregation, retention, and expiration operations for patient clinical observations.
/// </summary>
/// <!-- aidoc:v1 sig=70efcb8 -->
public class ObservationRepository : MongoRepository<PatientObservation>, IObservationRepository
{
private readonly ApiSettings _apiSettings;
@@ -34,6 +35,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <param name="database">The MongoDB database instance used to access the collection.</param>
/// <param name="logger">The logger used to record diagnostic and error information.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="apiSettings"/> is <see langword="null"/>.</exception>
/// <!-- aidoc:v1 sig=5a66d34 body=2164183 -->
public ObservationRepository(
IOptions<ApiSettings>? apiSettings,
IMongoDatabase database,
@@ -56,6 +58,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// Falls back to the default "patients_observations" collection name when not configured in the API settings.
/// </summary>
/// <returns>The collection name retrieved from the API settings, or "patients_observations" if not configured.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=23fb24b -->
public override string GetCollectionName()
{
return _apiSettings.PatientsObservations ?? "patients_observations";
@@ -70,6 +73,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <param name="code">The code identifying the observation type within the coding system.</param>
/// <param name="num">The maximum number of recent observations to return. Defaults to 2.</param>
/// <returns>An <see cref="IEnumerable{PatientObservation}"/> containing the matching observations ordered from newest to oldest.</returns>
/// <!-- aidoc:v1 sig=404377e body=0480966 -->
public async Task<IEnumerable<PatientObservation>> FindLastObservations(ObjectId patientId, string codingSystem,
string code, int num = 2)
{
@@ -96,6 +100,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <param name="codingSystem">The coding system to filter observations by.</param>
/// <param name="num">The maximum number of recent observations to return. Defaults to 10.</param>
/// <returns>A <see cref="List{PatientObservation}"/> containing the matching observations ordered from newest to oldest.</returns>
/// <!-- aidoc:v1 sig=09172c7 body=f40336d -->
public async Task<List<PatientObservation>> FindLastObservationsByCodingSystem(ObjectId patientId,
string codingSystem, int num = 10)
{
@@ -121,6 +126,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <param name="num">The maximum number of observations to return per observation name.</param>
/// <param name="filterObservations">Optional list of observation names to restrict the query to. When <see langword="null"/>, all distinct names are discovered.</param>
/// <returns>A <see cref="List{PatientObservation}"/> containing the aggregated latest observations across all matching names.</returns>
/// <!-- aidoc:v1 sig=0f4e126 body=0b43f32 -->
public async Task<List<PatientObservation>> AggregatedPatientLastObservations(ObjectId patientId, int num,
List<string>? filterObservations = null)
{
@@ -157,6 +163,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <param name="lastDate">The inclusive upper bound (UTC) for the observation <c>time</c> field.</param>
/// <param name="filterObservations">Optional list of observation names to restrict the query to. When <see langword="null"/>, all distinct names are discovered.</param>
/// <returns>A <see cref="List{PatientObservation}"/> containing the matching observations.</returns>
/// <!-- aidoc:v1 sig=605f95b body=2f3441d -->
public async Task<List<PatientObservation>> AggregatedPatientLastObservationsByLastDate(ObjectId patientId, int num,
DateTime lastDate, List<string>? filterObservations = null)
{
@@ -195,6 +202,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// A <see cref="List{PatientObservation}"/> containing the matching observations.
/// Returns an empty list when an exception occurs while querying the database.
/// </returns>
/// <!-- aidoc:v1 sig=442f63d body=77c0486 -->
public async Task<List<PatientObservation>> AggregatedPatientLastObservationsByField(ObjectId patientId,
List<Field>? filterObservations)
{
@@ -266,6 +274,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// A <see cref="List{BsonDocument}"/> with one document per time bucket.
/// Returns an empty list when an exception occurs while executing the pipeline.
/// </returns>
/// <!-- aidoc:v1 sig=43cc5aa body=792314e -->
public async Task<List<BsonDocument>> AggregatedPatientGroupedObservations(ObjectId patientId,
GroupedField groupedField)
{
@@ -550,6 +559,8 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <returns>A <see cref="Task"/> representing the asynchronous insert operation.</returns>
/// <exception cref="MongoWriteException">Rethrown after the maximum number of retries has been reached when a duplicate-key error keeps occurring.</exception>
/// <exception cref="Exception">Rethrown when an unexpected error occurs during the insert operation.</exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary states the method retries 'with a new ObjectId' on duplicate-key errors, but the catch block never assigns or generates a new ObjectId — the same patientObservation is passed to InsertOneAsync unchanged on each retry." -->
public new async Task InsertOneAsync(PatientObservation patientObservation)
{
const int maxRetries = 2; // Número máximo de reintentos
@@ -586,6 +597,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// </summary>
/// <param name="id">The <see cref="ObjectId"/> of the patient whose observations should be removed.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous delete operation.</returns>
/// <!-- aidoc:v1 sig=09e4e41 body=0e8105c -->
public async Task DeleteByPatientId(ObjectId id)
{
var filter = Builders<PatientObservation>.Filter.Eq(po => po.PatientId, id);
@@ -599,6 +611,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <returns>
/// An <see cref="IAsyncCursor{PatientObservation}"/> that can be enumerated to retrieve the patient's observations.
/// </returns>
/// <!-- aidoc:v1 sig=3727a3e body=9f79ea7 -->
public async Task<IAsyncCursor<PatientObservation>> FindByPatientIdAsync(ObjectId patientId)
{
var filter = Builders<PatientObservation>.Filter.Eq(ob => ob.PatientId, patientId);
@@ -615,6 +628,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// An <see cref="IAsyncCursor{PatientObservation}"/> containing the matching observations,
/// retrieved with a server-side batch size of 100.
/// </returns>
/// <!-- aidoc:v1 sig=6e7afc6 body=3957510 -->
public async Task<IAsyncCursor<PatientObservation>> FindByPatientIdAndCodingSystemAsync(ObjectId patientId,
string codingSystem, string name)
{
@@ -636,6 +650,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// </summary>
/// <param name="id">The <see cref="ObjectId"/> of the observation to delete.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous delete operation.</returns>
/// <!-- aidoc:v1 sig=78c6c5d body=8d17292 -->
public new async Task DeleteAsync(ObjectId id)
{
var filter = Builders<PatientObservation>.Filter.Eq(obs => obs.Id, id);
@@ -650,6 +665,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <param name="name">The observation name to filter by.</param>
/// <param name="retentionPolicyValue">The retention window expressed in days. Observations older than <c>UtcNow - retentionPolicyValue</c> days are removed.</param>
/// <returns>A <see cref="List{PatientObservation}"/> containing the documents that were deleted.</returns>
/// <!-- aidoc:v1 sig=db9f78a body=38e1006 -->
public async Task<List<PatientObservation>> DeleteOlderDaysAsync(string name, int retentionPolicyValue)
{
var dateLimit = DateTime.UtcNow.AddDays(-1 * retentionPolicyValue);
@@ -672,6 +688,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <param name="name">The observation name to filter by.</param>
/// <param name="retentionPolicyValue">The retention window expressed in seconds. Observations older than <c>UtcNow - retentionPolicyValue</c> seconds are removed.</param>
/// <returns>A <see cref="List{PatientObservation}"/> containing the documents that were deleted.</returns>
/// <!-- aidoc:v1 sig=9b16832 body=8605782 -->
public async Task<List<PatientObservation>> DeleteOlderSecondsAsync(string name, int retentionPolicyValue)
{
var dateLimit = DateTime.UtcNow.AddSeconds(-1 * retentionPolicyValue);
@@ -694,6 +711,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <param name="name">The observation name to apply the retention policy to.</param>
/// <param name="retentionPolicyValue">The maximum number of observations to retain. The remainder are deleted.</param>
/// <returns>A <see cref="List{PatientObservation}"/> containing the documents that were deleted. Returns an empty list when nothing had to be deleted.</returns>
/// <!-- aidoc:v1 sig=c385e27 body=8410fad -->
public async Task<List<PatientObservation>> DeleteOlderNumberAsync(string name, int retentionPolicyValue)
{
var builder = Builders<PatientObservation>.Filter;
@@ -724,6 +742,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <param name="patientid">The unique identifier of the patient.</param>
/// <param name="systemId">The external system identifier to look up.</param>
/// <returns><see langword="true"/> if a matching observation exists; otherwise, <see langword="false"/>.</returns>
/// <!-- aidoc:v1 sig=039b8ae body=13a2d36 -->
public async Task<bool> ExistBySystemId(ObjectId patientid, string systemId)
{
return await Collection.Find(Builders<PatientObservation>.Filter.And(
@@ -745,6 +764,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// A <see cref="Task{PatientObservation}"/> representing the asynchronous operation.
/// The task result contains the most recent matching observation, or <see langword="null"/> if no observation matches.
/// </returns>
/// <!-- aidoc:v1 sig=6152e35 body=332a506 -->
public async Task<PatientObservation?> FindLastObservationBeforeDate(ObjectId patientId, string? name,
DateTime date)
{
@@ -772,6 +792,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// A <see cref="Task{List{PatientObservation}}"/> representing the asynchronous operation.
/// The task result contains a list of matching observations, which may be empty.
/// </returns>
/// <!-- aidoc:v1 sig=87691b0 body=2ac50f6 -->
public async Task<List<PatientObservation>?> FindAnyWithSameDate(ObjectId patientId, string? name, DateTime date)
{
var builder = Builders<PatientObservation>.Filter;
@@ -792,6 +813,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <returns>
/// A <see cref="List{PatientObservation}"/> containing the matching observations, which may be empty.
/// </returns>
/// <!-- aidoc:v1 sig=c25141b body=58a25f4 -->
public async Task<List<PatientObservation>> FindAnyBeforeDate(ObjectId patientId, DateTime date)
{
var filterBuilder = Builders<PatientObservation>.Filter;
@@ -817,6 +839,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <returns>
/// A <see cref="List{PatientObservation}"/> containing the most recent observation for each distinct value.
/// </returns>
/// <!-- aidoc:v1 sig=fbdab74 body=42ee291 -->
public async Task<List<PatientObservation>> FindLatestUniqueValuesByName(ObjectId patientId, string name,
int? expires)
{
@@ -867,6 +890,8 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <returns>
/// A <see cref="List{PatientObservation}"/> containing one observation per unique (Location, Type) combination.
/// </returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_returns
/// "The actual return type is List<PatientObservation?> (nullable elements due to LastOrDefault()), but the doc references List{PatientObservation} without indicating nullability." -->
public async Task<List<PatientObservation?>> AggregatedPatientActiveIntravenousLinesObservations(ObjectId patientId)
{
var results = new List<PatientObservation>();
@@ -899,6 +924,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <returns>
/// A <see cref="Dictionary{ObjectId, DateTime}"/> mapping each patient's <see cref="ObjectId"/> to the UTC timestamp of their latest observation.
/// </returns>
/// <!-- aidoc:v1 sig=115ac00 body=29b2957 -->
public async Task<Dictionary<ObjectId, DateTime>> FindAllLastPatientObservationTime()
{
var group = new BsonDocument
@@ -950,6 +976,8 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// A <see cref="Task{PatientObservation}"/> representing the asynchronous operation.
/// The task result contains the <see cref="PatientObservation"/> if found; otherwise, <see langword="null"/>.
/// </returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_returns
/// "The cref references Task{PatientObservation} but the actual return type is Task<PatientObservation?}; the textual description correctly notes null behavior but the cref itself is missing the nullable annotation." -->
public async Task<PatientObservation?> FindById(ObjectId id)
{
var filter = Builders<PatientObservation>.Filter.Eq(o => o.Id, id);
@@ -967,6 +995,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// A <see cref="Task{List{PatientObservation}}"/> representing the asynchronous operation.
/// The task result contains a list of observations, which may be empty.
/// </returns>
/// <!-- aidoc:v1 sig=4837300 body=9950647 -->
public async Task<List<PatientObservation>?> FindByPatientId(ObjectId id)
{
var filter = Builders<PatientObservation>.Filter.Eq(o => o.PatientId, id);
@@ -982,6 +1011,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// </summary>
/// <param name="observation">The <see cref="PatientObservation"/> whose <see cref="ObjectId"/> identifies the document to update.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous update operation.</returns>
/// <!-- aidoc:v1 sig=738ce4b body=caca1ff -->
public async Task Update(PatientObservation observation)
{
await UpdateOneAsync(observation.Id, observation);
@@ -995,6 +1025,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <param name="id">The new <see cref="ObjectId"/> value to assign.</param>
/// <param name="oldId">The existing <see cref="ObjectId"/> value to replace.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous update operation.</returns>
/// <!-- aidoc:v1 sig=72ce1ca body=b9b81e9 -->
public async Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId)
{
await UpdateManyObjectIdAsync(nameId, id, oldId);
@@ -1005,6 +1036,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// </summary>
/// <param name="expiredObservations">The list of <see cref="PatientObservation"/> instances to mark as expired. The set of identifiers is used to build the update filter.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous update operation.</returns>
/// <!-- aidoc:v1 sig=c0d4f8c body=2cbb9ec -->
public async Task UpdateExpiredObservations(List<PatientObservation> expiredObservations)
{
var filter = Builders<PatientObservation>.Filter
@@ -1020,6 +1052,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <param name="patientObservations">The observations whose identifiers form the target set of the update.</param>
/// <param name="update">The <see cref="UpdateDefinition{PatientObservation}"/> describing the changes to apply to each matching document.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous update operation.</returns>
/// <!-- aidoc:v1 sig=9ef4ae8 body=5f5bfaf -->
public async Task UpdateMany(IEnumerable<PatientObservation> patientObservations,
UpdateDefinition<PatientObservation> update)
{
@@ -1034,6 +1067,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <returns>
/// An <see cref="IEnumerable{PatientObservation}"/> containing all observations.
/// </returns>
/// <!-- aidoc:v1 sig=8ac3146 body=bff76bc -->
public async Task<IEnumerable<PatientObservation>> FindAll()
{
var result = await Collection.FindAsync(_ => true);
@@ -1051,6 +1085,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// (in minutes). Observations whose <c>time</c> is older than <c>DateTime.Now - expires</c> minutes are marked as expired.
/// </param>
/// <returns>A <see cref="Task"/> representing the asynchronous update operation.</returns>
/// <!-- aidoc:v1 sig=3c6bca9 body=e2d9f44 -->
public async Task ExpireExpiredObservations(
List<ConfigObservation> configObservationsToExpire)
{
@@ -1095,6 +1130,10 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <returns>
/// An <see cref="IEnumerable{PatientObservation}"/> containing the matching non-expired observations.
/// </returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Summary states 'Observations with a null name are excluded from the result' unconditionally, but the null-name filter (Not(Eq(o => o.Name, null))) is only added inside the `if (filterObservations != null)` branch. When filterObservations is null, null-named observations are NOT excluded." -->
/// <!-- aidoc-review:v1 severity=high kind=mentions_removed_behavior
/// "Param description claims 'When null, all non-null named observations are considered', but when filterObservations is null the code adds no name-related filters at all - null-named observations are also returned (subject only to the not-expired filter)." -->
public async Task<IEnumerable<PatientObservation>> FindNotExpired(List<string?>? filterObservations)
{
var filterBuilder = Builders<PatientObservation>.Filter;
@@ -1129,6 +1168,10 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// Thrown when <paramref name="name"/> is null, empty, or whitespace,
/// or when its length exceeds 100 characters.
/// </exception>
/// <!-- aidoc-review:v1 severity=high kind=wrong_param_role
/// "<paramref name=\"fromDate\"/> is documented as 'inclusive lower bound', but the code uses Builders<>.Filter.Gt (strict greater-than), making it an exclusive lower bound." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_param_role
/// "<paramref name=\"name\"/> is documented as 'The regex pattern to match', but Regex.Escape(name) is applied, so it is matched as an escaped literal substring, not as a raw regex pattern." -->
public async Task<IEnumerable<PatientObservation>> FindByName(string name, DateTime? fromDate = null)
{
if (string.IsNullOrWhiteSpace(name))
@@ -1167,6 +1210,8 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <returns>
/// An <see cref="IFindFluent{PatientObservation, PatientObservation}"/> instance that can be used to further refine and execute the query.
/// </returns>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_summary
/// "The summary describes the query as 'paginated', but the code applies only sort and filter; no Skip/Limit (or other pagination) is performed on the IFindFluent." -->
public IFindFluent<PatientObservation, PatientObservation> GetPaginatedObservations(PaginationFilter filter)
{
// Crear variable con la clase que construye los filtros
@@ -1214,6 +1259,10 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// <returns>
/// An <see cref="IEnumerable{PatientObservation}"/> containing the matching observations ordered from newest to oldest.
/// </returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary states results are 'optionally bounded to a recent time window', but the code never applies the computed date filter to the query: `filterBuilder.And(dateFilter)` is invoked inside the `if (endAfter.HasValue)` block but its return value is discarded, so `endAfter` has no effect on the returned observations." -->
/// <!-- aidoc-review:v1 severity=high kind=mentions_removed_behavior
/// "The <param name=\"endAfter\"> description claims only observations with time >= UtcNow - endAfter are returned, yet the constructed `dateFilter` is never combined into the final `filters` passed to `FindAsync`." -->
public async Task<IEnumerable<PatientObservation>> FindLastNotExpiredObservatonsByPatient(ObjectId patientId,
string name, int? endAfter = null, int? num = null)
{
@@ -1254,6 +1303,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous index creation operation.</returns>
/// <exception cref="Exception">Rethrown when an error occurs while creating the indexes.</exception>
/// <!-- aidoc:v1 sig=4955da2 body=2d25714 -->
public override async Task CreateIndexes()
{
try
@@ -1296,6 +1346,7 @@ public class ObservationRepository : MongoRepository<PatientObservation>, IObser
/// A <see cref="List{String}"/> containing the observation names to aggregate over.
/// Returns an empty list if no observations exist for the patient.
/// </returns>
/// <!-- aidoc:v1 sig=b7f7b8f body=54374c4 -->
private async Task<List<string>> AggregatePatientObservations(ObjectId patientId,
List<string>? filterObservations = null)
{
@@ -9,6 +9,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Provides a MongoDB-backed repository implementation for PoCMapping entities.
/// </summary>
/// <!-- aidoc:v1 sig=34c4715 -->
public class PoCMappingRepository : MongoRepository<PoCMapping>, IPoCMappingRepository
{
private readonly ApiSettings _apiSettings;
@@ -30,6 +31,7 @@ public class PoCMappingRepository : MongoRepository<PoCMapping>, IPoCMappingRepo
/// Retrieves the name of the mappings collection from the API settings configuration.
/// </summary>
/// <returns>The mappings collection name as configured in <c>_apiSettings</c>.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=140c15b -->
public override string GetCollectionName()
{
return _apiSettings.Mappings;
@@ -40,6 +42,7 @@ public class PoCMappingRepository : MongoRepository<PoCMapping>, IPoCMappingRepo
/// </summary>
/// <param name="key">The unique identifier (Id) of the <see cref="PoCMapping"/> to look up.</param>
/// <returns>A Task TResult containing the matching PoCMapping, or <c>null</c> if no document with the specified key exists in the collection.</returns>
/// <!-- aidoc:v1 sig=05f7477 body=e2c98c4 -->
public async Task<PoCMapping?> FindByKey(string key)
{
var filterBuilder = Builders<PoCMapping>.Filter;
@@ -14,6 +14,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Repository implementation for managing Patient archive entities in MongoDB.
/// Provides CRUD operations for historical/archived patient data.
/// </summary>
/// <!-- aidoc:v1 sig=9d2c240 -->
public class PatientArchiveRepository : MongoRepository<Patient>, IPatientArchiveRepository
{
private readonly ApiSettings _apiSettings;
@@ -24,6 +25,7 @@ public class PatientArchiveRepository : MongoRepository<Patient>, IPatientArchiv
/// <param name="apiSettings">API settings containing collection names configuration.</param>
/// <param name="database">The MongoDB database instance.</param>
/// <exception cref="ArgumentNullException">Thrown when apiSettings is null.</exception>
/// <!-- aidoc:v1 sig=f8a321d body=d2b18a3 -->
public PatientArchiveRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
{
if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
@@ -34,6 +36,7 @@ public class PatientArchiveRepository : MongoRepository<Patient>, IPatientArchiv
/// Gets the name of the collection for archived patients.
/// </summary>
/// <returns>The collection name from API settings, or default "archive_patient".</returns>
/// <!-- aidoc:v1 sig=94e22ff body=76e5629 -->
public override string GetCollectionName()
{
return _apiSettings.ArchivePatient ?? "archive_patient";
@@ -44,6 +47,7 @@ public class PatientArchiveRepository : MongoRepository<Patient>, IPatientArchiv
/// </summary>
/// <param name="patientNumber">The patient number to search for.</param>
/// <returns>The Patient if found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=09c89ab body=8d2454d -->
public async Task<Patient?> FindByPatientNumber(string patientNumber)
{
if (string.IsNullOrWhiteSpace(patientNumber)) return null;
@@ -60,6 +64,7 @@ public class PatientArchiveRepository : MongoRepository<Patient>, IPatientArchiv
/// Retrieves all archived patients from the collection.
/// </summary>
/// <returns>A list of all Patient entities in the archive.</returns>
/// <!-- aidoc:v1 sig=e8bb639 body=57f77c8 -->
public async Task<List<Patient>> FindAll()
{
var filterBuilder = Builders<Patient>.Filter;
@@ -77,6 +82,8 @@ public class PatientArchiveRepository : MongoRepository<Patient>, IPatientArchiv
/// <param name="patientNumber">The patient number to search for.</param>
/// <param name="unitId">The unit ID (currently not used in query, kept for interface compatibility).</param>
/// <returns>The unique Patient if exactly one match is found; otherwise, null if multiple or none.</returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_summary
/// "Summary claims the method searches for an 'archived patient', but the code applies no archive-status filter; it only filters by patientNumber." -->
public async Task<Patient?> SearchByPatientNumberAndDistinctUnit(string patientNumber, ObjectId unitId)
{
if (string.IsNullOrWhiteSpace(patientNumber)) return null;
@@ -96,6 +103,8 @@ public class PatientArchiveRepository : MongoRepository<Patient>, IPatientArchiv
/// </summary>
/// <param name="obj">The Patient entity to insert or merge.</param>
/// <exception cref="Exception">Logs warning and silently fails on error.</exception>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_exception
/// "The method catches Exception internally and swallows it (logs a warning); it never throws Exception to the caller, so documenting it via <exception cref=\"Exception\"> is misleading." -->
public override async Task InsertOneAsync(Patient obj)
{
try
@@ -154,6 +163,7 @@ public class PatientArchiveRepository : MongoRepository<Patient>, IPatientArchiv
/// Creates the necessary indexes for the PatientArchive collection.
/// Creates an index on patientNumber for improved query performance.
/// </summary>
/// <!-- aidoc:v1 sig=4955da2 body=549d3bb -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions { Background = true, Unique = false };
@@ -12,6 +12,8 @@ namespace adas_core.Infrastructure.Repositories;
/// providing concrete persistence operations defined by the <see cref="IPatientCarePlanRepository"/> contract.
/// </summary>
/// <typeparam name="PatientCarePlan">The type of the patient care plan entity managed by this repository.</typeparam>
/// <!-- aidoc-review:v1 severity=medium kind=extra_param
/// "<typeparam name=\"PatientCarePlan\"> is invalid because PatientCarePlanRepository is not a generic class; PatientCarePlan is a concrete type argument to MongoRepository<T>, not a type parameter." -->
public class PatientCarePlanRepository : MongoRepository<PatientCarePlan>, IPatientCarePlanRepository
{
#region Properties
@@ -28,6 +30,7 @@ public class PatientCarePlanRepository : MongoRepository<PatientCarePlan>, IPati
/// <param name="patientid">The string identifier of the patient whose object identifiers will be updated.</param>
/// <param name="patientId">The new <see cref="ObjectId"/> to assign to the patient's records.</param>
/// <param name="oldId">The existing <see cref="ObjectId"/> to be replaced.</param>
/// <!-- aidoc:v1 sig=9a63bf8 body=94ba0df -->
public async Task UpdateManyObjectId(string patientid, ObjectId patientId, ObjectId oldId)
{
await UpdateManyObjectIdAsync(patientid, patientId, oldId);
@@ -61,6 +64,7 @@ public class PatientCarePlanRepository : MongoRepository<PatientCarePlan>, IPati
/// Returns the collection name for patient care plan data, using the configured setting if available or a default fallback otherwise.
/// </summary>
/// <returns>The patient care plan collection name from <c>_apiSettings.PatientCarePlan</c>, or <c>"patients_care_plan"</c> when the setting is null.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=c8bc19f -->
public override string GetCollectionName()
{
return _apiSettings.PatientCarePlan ?? "patients_care_plan";
@@ -72,6 +76,7 @@ public class PatientCarePlanRepository : MongoRepository<PatientCarePlan>, IPati
/// </summary>
/// <param name="patientId">The unique identifier of the patient whose care plans should be retrieved.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a list of <see cref="PatientCarePlan"/> objects associated with the specified patient, or an empty list if none are found.</returns>
/// <!-- aidoc:v1 sig=9706d89 body=fae3443 -->
public async Task<List<PatientCarePlan>> FindByPatientId(ObjectId patientId)
{
var result = await Collection.FindAsync(Builders<PatientCarePlan>.Filter.Eq(p => p.PatientId, patientId));
@@ -83,6 +88,7 @@ public class PatientCarePlanRepository : MongoRepository<PatientCarePlan>, IPati
/// </summary>
/// <param name="userId">The unique identifier of the user whose patient care plans are being queried.</param>
/// <returns>A list of <see cref="PatientCarePlan"/> instances matching the specified user identifier; an empty list is returned if no plans are found.</returns>
/// <!-- aidoc:v1 sig=7520aa9 body=3dd56f3 -->
public async Task<List<PatientCarePlan>> FindByUserId(ObjectId userId)
{
var result = await Collection.FindAsync(Builders<PatientCarePlan>.Filter.Eq(p => p.UserId, userId));
@@ -93,6 +99,7 @@ public class PatientCarePlanRepository : MongoRepository<PatientCarePlan>, IPati
/// Retrieves all patient care plans from the data store without applying any filter.
/// </summary>
/// <returns>A task that represents the asynchronous operation, containing a list of all <see cref="PatientCarePlan"/> records.</returns>
/// <!-- aidoc:v1 sig=6a558a7 body=faea989 -->
public async Task<List<PatientCarePlan>> FindAll()
{
var result = await Collection.Find(Builders<PatientCarePlan>.Filter.Empty).ToListAsync();
@@ -18,6 +18,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Provides a MongoDB-backed repository implementation for managing patient data, exposing patient-specific data access operations defined by the IPatientRepository contract.
/// </summary>
/// <!-- aidoc:v1 sig=c81c577 -->
public class PatientRepository : MongoRepository<Patient>, IPatientRepository
{
private readonly ApiSettings _apiSettings;
@@ -47,6 +48,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// or falling back to the default "patients" if the setting is null.
/// </summary>
/// <returns>The configured patients collection name, or "patients" as a default when the setting is not set.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=04f5507 -->
public override string GetCollectionName()
{
return _apiSettings.Patients ?? "patients";
@@ -58,6 +60,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="id">The unique identifier of the patient to locate.</param>
/// <returns>A <see cref="Patient"/> instance matching the provided id, or <c>null</c> if not found or on error.</returns>
/// <!-- aidoc:v1 sig=f97bb0d body=2c27a66 -->
public async Task<Patient?> FindById(ObjectId id)
{
try
@@ -80,6 +83,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="id">The point of care identifier used to locate the patient.</param>
/// <returns>A <see cref="Patient"/> instance if a match is found; otherwise, <c>null</c>.</returns>
/// <!-- aidoc:v1 sig=8a4443e body=e3fe55b -->
public async Task<Patient?> FindByPointOfCareId(ObjectId id)
{
try
@@ -103,6 +107,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// <param name="unit">The identifier of the unit to filter by.</param>
/// <param name="pointOfCare">The identifier of the point of care to filter by.</param>
/// <returns>The first matching <see cref="Patient"/>, or null if no patient is found or an error is encountered.</returns>
/// <!-- aidoc:v1 sig=9b461f1 body=c98f5c9 -->
public async Task<Patient> FindByUnitAndPocId(ObjectId unit, ObjectId pointOfCare)
{
try
@@ -129,6 +134,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="location">The location information used to locate the patient. Can be null.</param>
/// <returns>A <see cref="Patient"/> matching the location criteria, or null if no match is found or the location is null.</returns>
/// <!-- aidoc:v1 sig=556acef body=7ff7fec -->
public async Task<Patient?> FindByLocation(PatientLocation? location)
{
if (location == null)
@@ -155,6 +161,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// Asynchronously inserts a new <see cref="Patient"/> record, setting its creation date to the current UTC time. If the insertion fails but an existing patient with the same patient number is found at the same location, the exception is logged as a warning; otherwise, the error is logged and rethrown.
/// </summary>
/// <param name="patient">The <see cref="Patient"/> entity to insert into the data store.</param>
/// <!-- aidoc:v1 sig=334af9d body=f6ea95d -->
public override async Task InsertOneAsync(Patient patient)
{
try
@@ -183,6 +190,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// Updates an existing patient record, refreshing the update timestamp to the current UTC time before persisting the changes.
/// </summary>
/// <param name="patient">The patient entity containing the updated information to be saved.</param>
/// <!-- aidoc:v1 sig=f9d52dc body=06dccd6 -->
public async Task Update(Patient patient)
{
patient.UpdateDate = DateTime.UtcNow;
@@ -193,6 +201,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// Deletes a patient from the collection that matches the specified identifier.
/// </summary>
/// <param name="id">The unique identifier of the patient to remove.</param>
/// <!-- aidoc:v1 sig=3de1ad6 body=60a9b9b -->
public async Task Delete(ObjectId id)
{
var filter = Builders<Patient>.Filter.Eq(x => x.Id, id);
@@ -204,6 +213,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="id">The unique identifier of the patient whose location will be updated.</param>
/// <param name="location">The new location to assign to the patient.</param>
/// <!-- aidoc:v1 sig=a6d84a4 body=af93f9e -->
public async Task UpdateLocation(ObjectId id, PatientLocation location)
{
var patient = await FindById(id);
@@ -236,6 +246,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="id">The unique identifier of the patient whose location will be updated.</param>
/// <param name="location">The new point of care (location) identifier to assign to the patient.</param>
/// <!-- aidoc:v1 sig=ca2f737 body=b5de0cf -->
public async Task UpdateLocation(ObjectId id, ObjectId location)
{
var patient = await FindById(id);
@@ -255,6 +266,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="id">The unique identifier of the patient whose attending doctor is being updated.</param>
/// <param name="attendingDoctor">The new attending doctor to assign to the patient.</param>
/// <!-- aidoc:v1 sig=724f112 body=44fd27b -->
public async Task UpdateAttendingDoctor(ObjectId id, Person attendingDoctor)
{
var update = Builders<Patient>.Update
@@ -272,6 +284,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// <param name="patientNumber">The new patient number to apply when <paramref name="updatePatientNumber"/> is true.</param>
/// <param name="data">The new <see cref="Person"/> information to store for the patient.</param>
/// <param name="updatePatientNumber">Indicates whether the patient number should be updated as part of the operation; defaults to true.</param>
/// <!-- aidoc:v1 sig=06ac587 body=114be5c -->
public async Task UpdatePatientData(ObjectId id, string patientNumber, Person data, bool updatePatientNumber = true)
{
var filterBuilder = Builders<Patient>.Filter;
@@ -615,6 +628,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// <param name="unitIds">The list of unit identifiers used to filter patients.</param>
/// <param name="typeName">The name of the type to validate against the MasterListType enumeration.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a list of Patient objects matching the specified unit identifiers, or an empty list if the type name is invalid.</returns>
/// <!-- aidoc:v1 sig=6f3d195 body=74ee8d7 -->
public async Task<List<Patient>> GetPatientsByUnitIds(List<ObjectId> unitIds, string typeName)
{
var isParsed = Enum.TryParse<MasterListType>(typeName, out _);
@@ -630,6 +644,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="unitId">The unit identifier used to filter patients.</param>
/// <returns>The number of patients matching the specified unit identifier, or 0 if an error occurs.</returns>
/// <!-- aidoc:v1 sig=baa8175 body=e692f35 -->
public async Task<long> CountByUnitId(ObjectId unitId)
{
try
@@ -818,6 +833,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// Retrieves all <see cref="Patient"/> records from the data store.
/// </summary>
/// <returns>A task that represents the asynchronous operation, containing a list of all patients.</returns>
/// <!-- aidoc:v1 sig=e8bb639 body=c6cbf36 -->
public async Task<List<Patient>> FindAll()
{
return (await Collection.FindAsync(Builders<Patient>.Filter.Empty)).ToList();
@@ -829,6 +845,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="pointOfCare">The unit or point of care used to filter the patients.</param>
/// <returns>A task containing a list of <see cref="Patient"/> objects whose unit matches the specified point of care; an empty list is returned when no matches are found.</returns>
/// <!-- aidoc:v1 sig=c4523a3 body=eff26de -->
public async Task<List<Patient>> FindByPointOfCare(string pointOfCare)
{
var filterBuilder = Builders<Patient>.Filter;
@@ -844,6 +861,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="pointOfCare">The identifier of the point of care used to filter the patient records.</param>
/// <returns>A task that represents the asynchronous operation, containing a list of patients matching the specified point of care.</returns>
/// <!-- aidoc:v1 sig=1cea52d body=b9dfd95 -->
public async Task<List<Patient>> FindByPointOfCare(ObjectId pointOfCare)
{
var filterBuilder = Builders<Patient>.Filter;
@@ -932,6 +950,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="filter">The pagination and filtering criteria, including optional text, time range, unit, and point of care filters.</param>
/// <returns>A find fluent for the filtered and sorted patient query.</returns>
/// <!-- aidoc:v1 sig=6790d47 body=f65667b -->
public IFindFluent<Patient, Patient> GetPaginatedPatients(PaginationFilter filter)
{
var filterBuilder = Builders<Patient>.Filter;
@@ -981,6 +1000,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="date">The cutoff date; patients with an <c>UpdateDate</c> strictly earlier than this value, or with no <c>UpdateDate</c> set, will be returned.</param>
/// <returns>A task that resolves to a list of <see cref="Patient"/> instances matching the filter criteria.</returns>
/// <!-- aidoc:v1 sig=42988dc body=d938adb -->
public async Task<List<Patient>> FindPatientsNotUpdatedSince(DateTime date)
{
var filter = Builders<Patient>.Filter.Or(
@@ -999,6 +1019,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <returns>A task that resolves to a list of discharged <see cref="Patient"/> records,
/// or an empty list if the operation fails.</returns>
/// <!-- aidoc:v1 sig=c56ad55 body=600ef72 -->
public async Task<List<Patient>> FindDischargedPatients()
{
try
@@ -1022,6 +1043,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="updatedPatient">The patient entity containing the updated values and the identifier of the record to modify.</param>
/// <returns>The updated <see cref="Patient"/> after the modification is applied, or <c>null</c> if no matching document exists.</returns>
/// <!-- aidoc:v1 sig=5cf3377 body=b2c2664 -->
public async Task<Patient?> UpdateOne(Patient updatedPatient)
{
var filter = Builders<Patient>.Filter.Eq("_id", updatedPatient.Id);
@@ -1042,6 +1064,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// <param name="patientId">The unique identifier of the patient to update.</param>
/// <param name="person">The patient object containing the new values for the incoming data fields.</param>
/// <returns>The updated <see cref="Patient"/> document after the modification, or <c>null</c> if no document was found.</returns>
/// <!-- aidoc:v1 sig=c195b1f body=20e831b -->
public async Task<Patient?> UpdatePatientIncomingData(ObjectId patientId, Patient person)
{
var filter = Builders<Patient>.Filter.Eq("_id", patientId);
@@ -1064,6 +1087,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// <param name="patientId">The unique identifier of the patient whose data will be updated.</param>
/// <param name="person">The patient object containing the new demographic and clinical values to persist.</param>
/// <returns>The updated <see cref="Patient"/> document, or <c>null</c> if no patient with the specified identifier was found.</returns>
/// <!-- aidoc:v1 sig=a6fa876 body=4fc291c -->
public async Task<Patient?> UpdatePatientDemographicData(ObjectId patientId, Patient person)
{
var filter = Builders<Patient>.Filter.Eq("_id", patientId);
@@ -1084,6 +1108,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// <summary>
/// Creates MongoDB indexes for the Patient collection, including a unique index on the <c>patientNumber</c> field and a non-unique index on the <c>admTime</c> field, using background index creation.
/// </summary>
/// <!-- aidoc:v1 sig=4955da2 body=6e16010 -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions<Patient> { Background = true, Unique = false };
@@ -1111,6 +1136,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// <param name="requestFilter">The request containing the optional start and end time values used to build each range filter.</param>
/// <param name="filters">The collection of filter definitions to which the constructed filters are added.</param>
/// <param name="filterBuilder">The builder used to create the Gte and Lte filter definitions for each time range.</param>
/// <!-- aidoc:v1 sig=095d341 body=8b4f9c0 -->
private static void AddTimeFilters(FilteredRequest requestFilter, List<FilterDefinition<Patient>> filters,
FilterDefinitionBuilder<Patient> filterBuilder)
{
@@ -1164,6 +1190,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// </summary>
/// <param name="pointOfCare">The ObjectId of the point of care used to filter the patients.</param>
/// <returns>A task that represents the asynchronous operation, containing a list of patients matching the specified point of care.</returns>
/// <!-- aidoc:v1 sig=4945a00 body=b9dfd95 -->
public async Task<List<Patient>> FindAllByPointOfCareId(ObjectId pointOfCare)
{
var filterBuilder = Builders<Patient>.Filter;
@@ -1181,6 +1208,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// <param name="filters">The list of filter definitions to which the new filter will be appended.</param>
/// <param name="filter">The pagination filter containing the request criteria used to build the default filter.</param>
/// <param name="filterBuilder">The builder used to construct the MongoDB filter definitions for the <see cref="Patient"/> entity.</param>
/// <!-- aidoc:v1 sig=6206f14 body=1a8e3bd -->
private void AddDefaultFilters(List<FilterDefinition<Patient>> filters, PaginationFilter filter,
FilterDefinitionBuilder<Patient> filterBuilder)
{
@@ -1206,6 +1234,7 @@ public class PatientRepository : MongoRepository<Patient>, IPatientRepository
/// <param name="filters">The list of filter definitions to combine; when empty, an empty filter (match-all) is used.</param>
/// <param name="sort">The sort definition to apply to the query results.</param>
/// <returns>An <see cref="IFindFluent{TSource, TDocument}"/> configured with the combined filter and sort.</returns>
/// <!-- aidoc:v1 sig=6ee44b3 body=7b7fa02 -->
private IFindFluent<Patient, Patient> CreateFindFluent(List<FilterDefinition<Patient>> filters,
SortDefinition<Patient> sort)
{
@@ -14,6 +14,8 @@ namespace adas_core.Infrastructure.Repositories;
/// Represents a MongoDB-backed repository for <see cref="PoCSettings"/> entities, implementing the <see cref="IPoCSettingsRepository"/> contract to provide data access operations.
/// </summary>
/// <typeparam name="PoCSettings">The type of the settings entity managed by the repository.</typeparam>
/// <!-- aidoc-review:v1 severity=medium kind=extra_param
/// "PoCSettings is not a type parameter of PoCSettingsRepository; it is a generic type argument supplied to MongoRepository. The <typeparam> tag is incorrect." -->
public class PoCSettingsRepository : MongoRepository<PoCSettings>, IPoCSettingsRepository
{
private readonly ApiSettings _apiSettings;
@@ -36,6 +38,7 @@ public class PoCSettingsRepository : MongoRepository<PoCSettings>, IPoCSettingsR
/// Retrieves the collection name used for Proof of Concept (PoC) settings, returning the value from the API settings or the default "poc_settings" when no value is configured.
/// </summary>
/// <returns>The configured PoC settings collection name, or "poc_settings" as a fallback when <c>_apiSettings.PoCSettings</c> is null.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=1916b20 -->
public override string GetCollectionName()
{
return _apiSettings.PoCSettings ?? "poc_settings";
@@ -45,6 +48,7 @@ public class PoCSettingsRepository : MongoRepository<PoCSettings>, IPoCSettingsR
/// Deletes the PoCSettings document matching the specified identifier from the collection.
/// </summary>
/// <param name="id">The unique identifier of the PoCSettings document to delete.</param>
/// <!-- aidoc:v1 sig=3de1ad6 body=24b7498 -->
public async Task Delete(ObjectId id)
{
try
@@ -64,6 +68,7 @@ public class PoCSettingsRepository : MongoRepository<PoCSettings>, IPoCSettingsR
/// If an error occurs during the retrieval, the exception is logged and an empty list is returned as a fallback.
/// </summary>
/// <returns>A task that represents the asynchronous operation. The task result contains a list of all PoCSettings records, or an empty list if an error occurs.</returns>
/// <!-- aidoc:v1 sig=6810f78 body=f98d2ca -->
public async Task<List<PoCSettings>> FindAll()
{
try
@@ -84,6 +89,7 @@ public class PoCSettingsRepository : MongoRepository<PoCSettings>, IPoCSettingsR
/// </summary>
/// <param name="id">The <see cref="ObjectId"/> used to locate the PoCSettings document.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the matching <see cref="PoCSettings"/> or <c>null</c> if not found.</returns>
/// <!-- aidoc:v1 sig=de8c390 body=645f4b0 -->
public async Task<PoCSettings?> FindById(ObjectId id)
{
try
@@ -105,6 +111,7 @@ public class PoCSettingsRepository : MongoRepository<PoCSettings>, IPoCSettingsR
/// </summary>
/// <param name="location">The patient location provided as search criteria. Detailed attribute-based filtering by location fields is currently commented out.</param>
/// <returns>The first matching PoCSettings record, or null if no record is found.</returns>
/// <!-- aidoc:v1 sig=d3a4d30 body=e565bd9 -->
public async Task<PoCSettings?> FindByLocation(PatientLocation location)
{
try
@@ -137,6 +144,7 @@ public class PoCSettingsRepository : MongoRepository<PoCSettings>, IPoCSettingsR
/// Updates the existing PoC (Proof of Concept) settings asynchronously. If the update fails, the exception is logged and rethrown to the caller.
/// </summary>
/// <param name="pocSettings">The PoC settings entity to be updated, identified by its <c>Id</c>.</param>
/// <!-- aidoc:v1 sig=944ba55 body=9a9ca83 -->
public async Task Update(PoCSettings pocSettings)
{
try
@@ -153,6 +161,7 @@ public class PoCSettingsRepository : MongoRepository<PoCSettings>, IPoCSettingsR
/// <summary>
/// Creates the MongoDB indexes required for the <see cref="PoCSettings"/> collection, applying non-unique background indexing on the <c>patientLocation</c> field.
/// </summary>
/// <!-- aidoc:v1 sig=4955da2 body=b65c045 -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions { Background = true, Unique = false };
@@ -16,6 +16,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Represents a MongoDB-backed repository for <see cref="PointOfCare"/> entities, providing the persistence operations defined by the <see cref="IPointOfCareRepository"/> interface.
/// </summary>
/// <!-- aidoc:v1 sig=47f85a2 -->
public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareRepository
{
private readonly ApiSettings _apiSettings;
@@ -41,6 +42,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// Retrieves the collection name used for Locations operations from the API settings configuration.
/// </summary>
/// <returns>The configured Locations collection name retrieved from the API settings.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=3c89cf4 -->
public override string GetCollectionName()
{
return _apiSettings.Locations;
@@ -51,6 +53,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// If the base insert operation fails, the exception is written to the console and logged, then rethrown to preserve the original failure.
/// </summary>
/// <param name="pointOfCare">The <see cref="PointOfCare"/> entity to insert.</param>
/// <!-- aidoc:v1 sig=fb673ff body=2d2093f -->
public override async Task InsertOneAsync(PointOfCare pointOfCare)
{
try
@@ -70,6 +73,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// Any exception encountered during the delete operation is logged and rethrown to the caller.
/// </summary>
/// <param name="id">The unique identifier of the <see cref="PointOfCare"/> entity to remove.</param>
/// <!-- aidoc:v1 sig=3de1ad6 body=f09ede6 -->
public async Task Delete(ObjectId id)
{
try
@@ -90,6 +94,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="unitId">The identifier of the unit whose related <see cref="PointOfCare"/> records should be removed.</param>
/// <returns>A task that resolves to <c>true</c> when the records are deleted, or <c>false</c> when an error occurs during the operation.</returns>
/// <!-- aidoc:v1 sig=be3448b body=d89d1ff -->
public async Task<bool> DeleteManyByUnitId(ObjectId unitId)
{
try
@@ -110,6 +115,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// Updates an existing PointOfCare entity asynchronously in the data store.
/// </summary>
/// <param name="pointOfCare">The PointOfCare entity to update, identified by its Id.</param>
/// <!-- aidoc:v1 sig=f80d98a body=9bbdcdc -->
public async Task Update(PointOfCare pointOfCare)
{
try
@@ -128,6 +134,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="id">The ObjectId of the PointOfCare document to update.</param>
/// <param name="unit">The Unit object whose Name and Id values will be set on the matching document.</param>
/// <!-- aidoc:v1 sig=d74e094 body=6b7a6b3 -->
public async Task UpdateUnitId(ObjectId id, Unit unit)
{
var filterBuilder = Builders<PointOfCare>.Filter;
@@ -146,6 +153,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="pocId">The unique identifier of the Point of Care whose relay configuration will be updated.</param>
/// <param name="relayConfig">The collection of relays whose identifiers will be stored as the new relay configuration.</param>
/// <!-- aidoc:v1 sig=598eb3a body=e78ac25 -->
public async Task UpdateRelayConfig(ObjectId pocId, List<Relay> relayConfig)
{
var filterBuilder = Builders<PointOfCare>.Filter;
@@ -161,6 +169,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="pocId">The identifier of the point of care whose relay configuration will be updated.</param>
/// <param name="relayConfig">The new list of relay identifiers to assign to the point of care's configuration.</param>
/// <!-- aidoc:v1 sig=784ef54 body=8ee7aff -->
public async Task UpdateRelayConfig(ObjectId pocId, List<ObjectId> relayConfig)
{
var filterBuilder = Builders<PointOfCare>.Filter;
@@ -176,6 +185,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="id">The unique identifier of the <see cref="PointOfCare"/> entity to update.</param>
/// <param name="configuration">The new configuration values to apply to the entity.</param>
/// <!-- aidoc:v1 sig=1874ae4 body=c5f4db7 -->
public async Task UpdateConfiguration(ObjectId id, PointOfCareConfiguration configuration)
{
var filterBuilder = Builders<PointOfCare>.Filter;
@@ -193,6 +203,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="id">The unique <see cref="ObjectId"/> of the point of care to retrieve.</param>
/// <returns>A <see cref="PointOfCare"/> if a matching record is found; otherwise, <c>null</c>.</returns>
/// <!-- aidoc:v1 sig=2826028 body=1db2247 -->
public async Task<PointOfCare?> FindById(ObjectId id)
{
try
@@ -215,6 +226,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// <param name="status">The point of care status used to filter the results.</param>
/// <param name="excludeVirtual">When <c>true</c>, filters out entries whose bed matches one of the known <see cref="VirtualPointOfCare"/> values; otherwise virtual entries are included.</param>
/// <returns>A task that resolves to an <see cref="IEnumerable{PointOfCare}"/> containing the matching entries, or an empty collection if the query fails.</returns>
/// <!-- aidoc:v1 sig=66efb59 body=346b01e -->
public async Task<IEnumerable<PointOfCare>> FindByUnitAndStatus(ObjectId unitId, StatusEnum.PointOfCare status,
bool excludeVirtual = false)
{
@@ -292,6 +304,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="unit">The identifier of the unit whose points of care should be retrieved.</param>
/// <returns>A task that yields a collection of <see cref="PointOfCare"/> instances matching the given unit, or <c>null</c> if the search fails.</returns>
/// <!-- aidoc:v1 sig=1265646 body=709d354 -->
public async Task<IEnumerable<PointOfCare>?> FindAllByUnitId(ObjectId unit)
{
try
@@ -314,6 +327,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="room">The room identifier used to filter the point-of-care records.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a collection of matching <see cref="PointOfCare"/> entries, or <see langword="null"/> if the search fails.</returns>
/// <!-- aidoc:v1 sig=d9b8bd7 body=11151e4 -->
public async Task<IEnumerable<PointOfCare>?> FindByRoom(string room)
{
try
@@ -336,6 +350,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="bed">The bed identifier used to filter the point of care records.</param>
/// <returns>A task containing an enumerable collection of matching <see cref="PointOfCare"/> records, or null if an error occurs.</returns>
/// <!-- aidoc:v1 sig=27196b1 body=358ac53 -->
public async Task<IEnumerable<PointOfCare>?> FindByBed(string bed)
{
try
@@ -359,6 +374,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// <param name="filter">The MongoDB filter definition used to match the desired <see cref="PointOfCare"/> documents.</param>
/// <param name="projection">An optional projection definition to limit or transform the fields returned in each document. When <c>null</c>, the full documents are returned.</param>
/// <returns>A task that represents the asynchronous operation, containing a list of <see cref="PointOfCare"/> documents that match the filter.</returns>
/// <!-- aidoc:v1 sig=18993a9 body=c2bab2a -->
public async Task<List<PointOfCare>> FindByFilter(FilterDefinition<PointOfCare> filter,
ProjectionDefinition<PointOfCare>? projection = null)
{
@@ -372,6 +388,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="unitId">The identifier of the unit whose point-of-care entries should be counted.</param>
/// <returns>A <see cref="Task{Int64}"/> that resolves to the number of matching point-of-care documents for the given unit.</returns>
/// <!-- aidoc:v1 sig=baa8175 body=a7b09ba -->
public async Task<long> CountByUnitId(ObjectId unitId)
{
try
@@ -446,6 +463,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="pocId">The unique identifier of the point of care whose configuration is being requested.</param>
/// <returns>A <see cref="Task{PointOfCare}"/> containing the matching <see cref="PointOfCare"/> with its configuration, or <c>null</c> if no record exists for the given identifier.</returns>
/// <!-- aidoc:v1 sig=8e7499c body=da257e7 -->
public async Task<PointOfCare?> GetPoCConfiguration(ObjectId pocId)
{
var filter = Builders<PointOfCare>.Filter.Eq(p => p.Id, pocId);
@@ -461,6 +479,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// Retrieves all <see cref="PointOfCare"/> records from the underlying data store using an empty filter.
/// </summary>
/// <returns>A <see cref="Task{TResult}"/> containing a <see cref="List{T}"/> of <see cref="PointOfCare"/> items, or <c>null</c> when no results are returned.</returns>
/// <!-- aidoc:v1 sig=54c1971 body=b4b56a0 -->
public async Task<List<PointOfCare>?> GetAll()
{
var filter = Builders<PointOfCare>.Filter.Empty;
@@ -472,6 +491,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="id">The unique identifier of the point of care to retrieve.</param>
/// <returns>A task that represents the asynchronous operation, containing the matching <see cref="PointOfCare"/> with its resolved beacon, camera, and relay configuration, or <c>null</c> if not found.</returns>
/// <!-- aidoc:v1 sig=3a998f5 body=6d67850 -->
public async Task<PointOfCare?> FindByIdAllConfig(ObjectId id)
{
return await Collection.Aggregate()
@@ -515,6 +535,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// contra el total de cámaras en uso, independientemente del volumen de datos.
/// </remarks>
/// <returns>Un conjunto hash con los <see cref="ObjectId"/> de las cámaras en uso.</returns>
/// <!-- aidoc:v1 sig=f6346fe body=c7c2683 -->
public async Task<HashSet<ObjectId>> FindAllIdCamerasInUse()
{
var distinctIds = await Collection
@@ -527,6 +548,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// Retrieves all distinct beacon identifiers currently referenced by any point-of-care configuration.
/// </summary>
/// <returns>A set containing the unique <see cref="ObjectId"/> values of beacons in use across all point-of-care records.</returns>
/// <!-- aidoc:v1 sig=7e41dd8 body=2dfc33a -->
public async Task<HashSet<ObjectId>> FindAllIdBeaconsInUse()
{
var distinctIds = await Collection
@@ -541,6 +563,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="unitId">The identifier of the unit used to filter the points of care.</param>
/// <returns>A task that returns a collection of PointOfCare with their associated device lists populated, or null if an error occurs during the query.</returns>
/// <!-- aidoc:v1 sig=74ce5ed body=bc6b30b -->
public async Task<IEnumerable<PointOfCare>?> FindAllByUnitIdWithDevices(ObjectId unitId)
{
try
@@ -592,6 +615,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// Retrieves the set of distinct relay identifiers currently referenced by any <see cref="PointOfCare"/> configuration in the collection.
/// </summary>
/// <returns>A <see cref="HashSet{T}"/> of <see cref="ObjectId"/> values containing all unique relay IDs found across the <c>configuration.relayIdList</c> field of every document.</returns>
/// <!-- aidoc:v1 sig=7d4add8 body=4904eff -->
public async Task<HashSet<ObjectId>> FindAllIdRelaysInUse()
{
var distinctIds = await Collection
@@ -605,6 +629,8 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// Retrieves all point-of-care configurations, joining each configuration with its associated light beacons, cameras, and relays through MongoDB lookups and projecting the combined result into a flattened <see cref="PointOfCare"/> structure.
/// </summary>
/// <returns>A task that resolves to a list of <see cref="PointOfCare"/> objects enriched with the corresponding beacon, camera, and relay details, or <c>null</c> when no configurations are found.</returns>
/// <!-- aidoc-review:v1 severity=medium kind=wrong_returns
/// "Documentation states the method returns 'null when no configurations are found', but the implementation uses pipeline.ToListAsync() which returns an empty list (not null) when no documents exist. The nullable return type annotation does not match the actual runtime behavior." -->
public async Task<List<PointOfCare>?> GetAllConfigs()
{
var pipeline = Collection.Aggregate()
@@ -655,6 +681,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// Uses an empty filter to return every record and returns a nullable list that may be null if no results are found.
/// </summary>
/// <returns>A task that represents the asynchronous operation, containing a list of <see cref="PointOfCare"/> objects with the projected fields, or <c>null</c> if no matching records exist.</returns>
/// <!-- aidoc:v1 sig=7d0cd41 body=44afaf5 -->
public async Task<List<PointOfCare>?> GetAllLocationInfo()
{
var filter = Builders<PointOfCare>.Filter.Empty;
@@ -675,6 +702,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="filter">The pagination and filtering criteria. If <c>FilteredRequest</c> is null, no additional filters are applied.</param>
/// <returns>An <see cref="IFindFluent{PointOfCare, PointOfCare}"/> representing the resulting MongoDB query with the applied filters and sort.</returns>
/// <!-- aidoc:v1 sig=63378f1 body=ab03c99 -->
public IFindFluent<PointOfCare, PointOfCare> GetPaginatedPoCs(PaginationFilter filter)
{
var filterBuilder = Builders<PointOfCare>.Filter;
@@ -742,6 +770,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// <summary>
/// Creates MongoDB indexes for the <see cref="PointOfCare"/> collection on the <c>unitId</c>, <c>room</c>, and <c>bed</c> fields, using background creation and non-unique constraints, to optimize query performance.
/// </summary>
/// <!-- aidoc:v1 sig=4955da2 body=b988d70 -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions { Background = true, Unique = false };
@@ -760,6 +789,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// </summary>
/// <param name="id">The unique identifier of the point-of-care record to update.</param>
/// <param name="status">The new status value to apply to the point-of-care record.</param>
/// <!-- aidoc:v1 sig=ad30072 body=87cbbaf -->
public async Task UpdateStatus(ObjectId id, StatusEnum.PointOfCare status)
{
var filterBuilder = Builders<PointOfCare>.Filter;
@@ -777,6 +807,7 @@ public class PointOfCareRepository : MongoRepository<PointOfCare>, IPointOfCareR
/// <param name="filters">The list of filter definitions to be combined; an empty list results in no filtering.</param>
/// <param name="sort">The sort definition applied to the resulting query.</param>
/// <returns>An <see cref="IFindFluent{PointOfCare, PointOfCare}"/> representing the filtered and sorted query.</returns>
/// <!-- aidoc:v1 sig=76fee2f body=51d06bc -->
private IFindFluent<PointOfCare, PointOfCare> CreateFindFluent(List<FilterDefinition<PointOfCare>> filters,
SortDefinition<PointOfCare> sort)
{
@@ -13,6 +13,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <remarks>
/// Inherits the generic MongoDB persistence capabilities of <see cref="MongoRepository{TDocument}"/>, specializing them for the <see cref="PumpAlarmEvent"/> entity type.
/// </remarks>
/// <!-- aidoc:v1 sig=bf52831 -->
public class PumpAlarmEventRepository : MongoRepository<PumpAlarmEvent>, IPumpAlarmEventRepository
{
private readonly ApiSettings _apiSettings;
@@ -88,6 +89,15 @@ public class PumpAlarmEventRepository : MongoRepository<PumpAlarmEvent>, IPumpAl
await Collection.InsertOneAsync(alarmEvent);
}
/// <summary>
/// Asynchronously retrieves <see cref="PumpAlarmEvent"/> records for the specified device, optionally constrained by an inclusive time range and a maximum result count.
/// </summary>
/// <param name="deviceId">The identifier of the device whose alarm events are queried.</param>
/// <param name="from">Optional inclusive lower bound on the event time; when <see langword="null"/>, no lower bound is applied.</param>
/// <param name="to">Optional inclusive upper bound on the event time; when <see langword="null"/>, no upper bound is applied.</param>
/// <param name="limit">Optional maximum number of events to return; when <see langword="null"/>, all matching events are returned.</param>
/// <returns>A task producing the matching <see cref="PumpAlarmEvent"/> records ordered by time in descending order.</returns>
/// <!-- aidoc:v1 sig=ea193a8 body=0e52ba3 -->
public async Task<IEnumerable<PumpAlarmEvent>> FindByDeviceIdAsync(string deviceId, DateTime? from = null,
DateTime? to = null, int? limit = null)
{
@@ -111,6 +121,8 @@ public class PumpAlarmEventRepository : MongoRepository<PumpAlarmEvent>, IPumpAl
/// <param name="deviceId">The identifier of the device whose latest alarm event is being retrieved.</param>
/// <returns>A <see cref="Task{PumpAlarmEvent}"/> that yields the latest <see cref="PumpAlarmEvent"/> associated with <paramref name="deviceId"/>, or <c>null</c> if no matching event is found.</returns>
/// <!-- aidoc:v1 sig=f0fbfb3 body=088b34a -->
/// <!-- aidoc-review:v1 severity=low kind=wrong_returns
/// "The <returns> tag references Task{PumpAlarmEvent} without the nullable annotation, while the actual return type is Task<PumpAlarmEvent?> (though the description text does mention nullability)." -->
public async Task<PumpAlarmEvent?> FindLastByDeviceIdAsync(string deviceId)
{
return await Collection
@@ -11,6 +11,7 @@ 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;
@@ -33,6 +34,7 @@ public class PumpAlarmStateRepository : MongoRepository<PumpAlarmState>, IPumpAl
/// 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";
@@ -77,6 +79,7 @@ public class PumpAlarmStateRepository : MongoRepository<PumpAlarmState>, IPumpAl
/// <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);
@@ -128,6 +131,7 @@ public class PumpAlarmStateRepository : MongoRepository<PumpAlarmState>, IPumpAl
/// <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);
@@ -145,6 +149,7 @@ public class PumpAlarmStateRepository : MongoRepository<PumpAlarmState>, IPumpAl
/// 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);
@@ -155,6 +160,7 @@ public class PumpAlarmStateRepository : MongoRepository<PumpAlarmState>, IPumpAl
/// </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();
@@ -167,6 +173,7 @@ public class PumpAlarmStateRepository : MongoRepository<PumpAlarmState>, IPumpAl
/// <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);
@@ -15,6 +15,7 @@ namespace adas_core.Infrastructure.Repositories
/// Repositorio de archivo para observaciones de bombas.
/// Colección: archive_pumpobservations (configurable por ApiSettings.ArchivePumpObservations).
/// </summary>
/// <!-- aidoc:v1 sig=46323e9 -->
public class PumpArchiveRepository : MongoRepository<PumpObservation>, IPumpArchiveRepository
{
private readonly ApiSettings _apiSettings;
@@ -76,6 +77,7 @@ namespace adas_core.Infrastructure.Repositories
/// Asynchronously inserts a <see cref="PumpObservation"/> into the underlying MongoDB collection.
/// </summary>
/// <param name="obs">The pump observation to persist.</param>
/// <!-- aidoc:v1 sig=2e9b63d body=ff40c9a -->
public async Task InsertAsync(PumpObservation obs)
{
await Collection.InsertOneAsync(obs);
@@ -85,6 +87,7 @@ namespace adas_core.Infrastructure.Repositories
/// Asynchronously inserts a batch of pump observations into the underlying data store. If the collection is empty, the method completes without performing any insertion.
/// </summary>
/// <param name="observations">The pump observations to insert into the collection.</param>
/// <!-- aidoc:v1 sig=1891edb body=80cfb77 -->
public async Task InsertManyAsync(IEnumerable<PumpObservation> observations)
{
var list = observations as IList<PumpObservation> ?? observations.ToList();
@@ -101,6 +104,7 @@ namespace adas_core.Infrastructure.Repositories
/// <param name="to">Optional inclusive upper bound for the observation time. When provided, only observations on or before this time are returned.</param>
/// <param name="limit">Optional maximum number of observations to return. When null, all matching observations are returned.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains an <see cref="IEnumerable{PumpObservation}"/> of matching observations ordered from newest to oldest.</returns>
/// <!-- aidoc:v1 sig=d24c731 body=afb5adf -->
public async Task<IEnumerable<PumpObservation>> FindByPatientIdAsync(
ObjectId patientId, DateTime? from = null, DateTime? to = null, int? limit = null)
{
@@ -124,6 +128,7 @@ namespace adas_core.Infrastructure.Repositories
/// Deletes all pump observations whose recording time is earlier than the specified cutoff date.
/// </summary>
/// <param name="addDays">The cutoff date; observations with a timestamp before this value are removed.</param>
/// <!-- aidoc:v1 sig=f776d6a body=426aa60 -->
public async Task DeleteBeforeDate(DateTime addDays)
{
var filter = Builders<PumpObservation>.Filter.Lt(x => x.Time, addDays);
@@ -17,6 +17,8 @@ namespace adas_core.Infrastructure.Repositories
/// As a specialized repository inheriting from <see cref="MongoRepository{PumpObservation}"/>, this class
/// reuses the base MongoDB storage capabilities while exposing the pump observation-specific repository contract.
/// </remarks>
/// <!-- aidoc-review:v1 severity=medium kind=extra_param
/// "The <typeparam name=\"PumpObservation\"> tag is incorrect: PumpObservationRepository is not a generic class, so it has no type parameters." -->
public class PumpObservationRepository : MongoRepository<PumpObservation>, IPumpObservationRepository
{
private readonly ApiSettings _apiSettings;
@@ -38,6 +40,7 @@ namespace adas_core.Infrastructure.Repositories
/// Retrieves the collection name used for pump observations, returning the configured value from API settings if available, or falling back to the default "pump_observations" name when no custom configuration is provided.
/// </summary>
/// <returns>The configured pump observations collection name from API settings, or the default "pump_observations" string if the setting is null.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=711309f -->
public override string GetCollectionName()
{
return _apiSettings.PumpObservations ?? "pump_observations";
@@ -77,6 +80,7 @@ namespace adas_core.Infrastructure.Repositories
/// Asynchronously inserts a pump observation into the underlying collection.
/// </summary>
/// <param name="obs">The pump observation document to be persisted.</param>
/// <!-- aidoc:v1 sig=2e9b63d body=ff40c9a -->
public async Task InsertAsync(PumpObservation obs)
{
await Collection.InsertOneAsync(obs);
@@ -86,6 +90,7 @@ namespace adas_core.Infrastructure.Repositories
/// Inserts a batch of pump observations into the underlying collection in a single operation. Returns immediately when the input is null or contains no elements, performing no insertion in those cases.
/// </summary>
/// <param name="observations">The pump observations to insert. A null or empty collection results in a no-op.</param>
/// <!-- aidoc:v1 sig=9b8dfd0 body=13df81e -->
public async Task InsertManyAsync(IEnumerable<PumpObservation>? observations)
{
if (observations == null) return;
@@ -104,6 +109,7 @@ namespace adas_core.Infrastructure.Repositories
/// <param name="to">Optional end timestamp; when provided, only observations with a time less than or equal to this value are returned.</param>
/// <param name="limit">Optional maximum number of observations to return; when not provided, all matching observations are returned.</param>
/// <returns>A task that represents the asynchronous operation, containing the collection of matching <see cref="PumpObservation"/> records.</returns>
/// <!-- aidoc:v1 sig=c4c17bd body=fccb1f4 -->
public async Task<IEnumerable<PumpObservation>> FindByDeviceIdAsync(
string deviceId,
DateTime? from = null,
@@ -136,6 +142,7 @@ namespace adas_core.Infrastructure.Repositories
/// <param name="to">Optional inclusive upper bound for the observation time. When null, no upper time bound is applied.</param>
/// <param name="limit">Optional maximum number of observations to return. When null, all matching observations are returned.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the matching pump observations sorted by time in descending order.</returns>
/// <!-- aidoc:v1 sig=7a9379f body=b1db477 -->
public async Task<IEnumerable<PumpObservation>> FindByPatientAsync(
ObjectId patientId,
DateTime? from = null,
@@ -205,6 +212,7 @@ namespace adas_core.Infrastructure.Repositories
/// </summary>
/// <param name="deviceId">The unique identifier of the device whose latest pump observation should be retrieved.</param>
/// <returns>A task that resolves to the most recent <see cref="PumpObservation"/> for the device, or <c>null</c> if no observation is found.</returns>
/// <!-- aidoc:v1 sig=c025146 body=088b34a -->
public async Task<PumpObservation?> FindLastByDeviceIdAsync(string deviceId)
{
return await Collection
@@ -218,6 +226,7 @@ namespace adas_core.Infrastructure.Repositories
/// </summary>
/// <param name="patientId">The optional patient identifier used to filter the pump observations.</param>
/// <returns>A task that represents the asynchronous operation, containing a collection of pump observations matching the given patient identifier.</returns>
/// <!-- aidoc:v1 sig=db5b147 body=51d8815 -->
public async Task<IEnumerable<PumpObservation>> FindByPatientId(ObjectId? patientId)
{
return await Collection.Find(x => x.PatientId == patientId).ToListAsync();
@@ -230,6 +239,7 @@ namespace adas_core.Infrastructure.Repositories
/// <param name="patientId">The identifier of the patient whose observations are being retrieved.</param>
/// <param name="num">The maximum number of observations to consider before deduplication. Defaults to 100.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a list of distinct <see cref="PumpObservation"/> entries for the patient, ordered from most recent to oldest.</returns>
/// <!-- aidoc:v1 sig=0c8097f body=4281403 -->
public async Task<List<PumpObservation>> AggregatedPatientLastObservations(ObjectId patientId, int num = 100)
{
var filterBuilder = Builders<PumpObservation>.Filter;
@@ -252,6 +262,7 @@ namespace adas_core.Infrastructure.Repositories
/// Deletes all records whose <c>PatientId</c> matches the specified patient identifier.
/// </summary>
/// <param name="patientId">The patient identifier whose associated records should be removed; may be <c>null</c>.</param>
/// <!-- aidoc:v1 sig=e8c536a body=395df12 -->
public async Task DeleteByPatientId(ObjectId? patientId)
{
await Collection.DeleteManyAsync(x => x.PatientId == patientId);
@@ -264,6 +275,7 @@ namespace adas_core.Infrastructure.Repositories
/// <param name="days">The age threshold in days. Observations with a <c>Time</c> older than <c>DateTime.UtcNow - days</c> are eligible for deletion.</param>
/// <param name="name">Optional name used to further restrict the deletion to observations with a matching <c>Name</c> value. If null or empty, the name filter is not applied.</param>
/// <returns>The number of <see cref="PumpObservation"/> documents that were deleted.</returns>
/// <!-- aidoc:v1 sig=102a371 body=9c5bcf4 -->
public async Task<long> DeleteOlderThanDaysAsync(int days, string? name = null)
{
var limitDate = DateTime.UtcNow.AddDays(-days);
@@ -281,6 +293,7 @@ namespace adas_core.Infrastructure.Repositories
/// </summary>
/// <param name="maxCount">The maximum number of most recent records to keep per device.</param>
/// <returns>The total number of observations deleted across all devices.</returns>
/// <!-- aidoc:v1 sig=295122a body=e030407 -->
public async Task<long> DeleteKeepLastNAsync(int maxCount)
{
// Para cada DeviceId:
@@ -320,6 +333,7 @@ namespace adas_core.Infrastructure.Repositories
/// <param name="oldId">The current <see cref="ObjectId"/> value used to match documents; if <c>null</c>, the filter matches documents where the field is null.</param>
/// <returns>The number of documents that were modified by the update operation.</returns>
/// <exception cref="ArgumentException">Thrown when <paramref name="fieldName"/> is null, empty, or whitespace.</exception>
/// <!-- aidoc:v1 sig=260cb78 body=f2c2192 -->
public async Task<long> UpdateManyObjectIdByFieldAsync(string fieldName, ObjectId newId, ObjectId? oldId)
{
if (string.IsNullOrWhiteSpace(fieldName))
@@ -386,6 +400,7 @@ namespace adas_core.Infrastructure.Repositories
/// <param name="patientId">The unique identifier of the patient whose observations are being queried.</param>
/// <param name="name">The name of the pump observation to filter by. If null, empty, or whitespace, an empty list is returned.</param>
/// <returns>A task representing the asynchronous operation, containing a list of the matching pump observations (at most two) sorted from newest to oldest.</returns>
/// <!-- aidoc:v1 sig=2ba6244 body=efdef74 -->
public async Task<List<PumpObservation>> FindLastObservations(ObjectId patientId, string name)
{
if (string.IsNullOrWhiteSpace(name))
@@ -11,6 +11,7 @@ namespace adas_core.Infrastructure.Repositories
/// Provides a repository implementation for <see cref="PumpState"/> entities backed by a MongoDB data store.
/// </summary>
/// <remarks>Inherits base functionality from <see cref="MongoRepository{T}"/> and implements the <see cref="IPumpStateRepository"/> contract.</remarks>
/// <!-- aidoc:v1 sig=e8fa3b3 -->
public class PumpStateRepository : MongoRepository<PumpState>, IPumpStateRepository
{
private readonly ApiSettings _apiSettings;
@@ -32,6 +33,7 @@ namespace adas_core.Infrastructure.Repositories
/// Retrieves the collection name for pump states, returning the configured value from API settings or the default name "pump_states" when the setting is not provided.
/// </summary>
/// <returns>The configured pump states collection name, or the default value "pump_states" if the setting is null.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=31eaf80 -->
public override string GetCollectionName()
{
return _apiSettings.PumpStates ?? "pump_states";
@@ -71,6 +73,7 @@ namespace adas_core.Infrastructure.Repositories
/// </summary>
/// <param name="deviceId">The unique identifier of the device whose pump state should be looked up.</param>
/// <returns>A <see cref="PumpState"/> instance if a matching record is found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=bab429b body=ea4c529 -->
public async Task<PumpState?> FindByDeviceIdAsync(string deviceId)
{
return await Collection.Find(x => x.DeviceId == deviceId).FirstOrDefaultAsync();
@@ -80,6 +83,7 @@ namespace adas_core.Infrastructure.Repositories
/// Inserts the specified <see cref="PumpState"/> or updates the existing one identified by its <c>DeviceId</c>. If a matching record is found, its identifier is reused; otherwise a new identifier is generated when the provided one is empty.
/// </summary>
/// <param name="state">The pump state to persist. Its <c>Id</c> is preserved or assigned based on whether a record with the same <c>DeviceId</c> already exists.</param>
/// <!-- aidoc:v1 sig=5ce0824 body=9517005 -->
public async Task UpsertAsync(PumpState state)
{
var existing = await Collection
@@ -102,6 +106,7 @@ namespace adas_core.Infrastructure.Repositories
/// Asynchronously retrieves all <see cref="PumpState"/> records from the data store.
/// </summary>
/// <returns>A task that represents the asynchronous operation, containing an <see cref="IEnumerable{T}"/> of all <see cref="PumpState"/> records; an empty collection is returned if no records exist.</returns>
/// <!-- aidoc:v1 sig=22c3173 body=c62f88b -->
public async Task<IEnumerable<PumpState>> GetAllAsync()
{
return await Collection.Find(Builders<PumpState>.Filter.Empty).ToListAsync();
@@ -10,6 +10,8 @@ namespace adas_core.Infrastructure.Repositories;
/// Represents a MongoDB repository responsible for managing archived patient recording alerts, exposing archive-specific data access operations through the recording alert archive repository contract.
/// </summary>
/// <typeparam name="PatientRecordingAlert">The type of the patient recording alert entity persisted in the archive.</typeparam>
/// <!-- aidoc-review:v1 severity=low kind=extra_param
/// "The <typeparam name=\"PatientRecordingAlert\"> tag is applied to a non-generic class; RecordingAlertArchiveRepository declares no type parameters of its own. The type parameter belongs to the base class MongoRepository<PatientRecordingAlert> and should not appear on this type's documentation." -->
public class RecordingAlertArchiveRepository : MongoRepository<PatientRecordingAlert>, IRecordingAlertArchiveRepository
{
private readonly ApiSettings _apiSettings;
@@ -34,6 +36,7 @@ public class RecordingAlertArchiveRepository : MongoRepository<PatientRecordingA
/// Gets the collection name for archive patients recording alerts, returning the configured value from API settings or a default name when no setting is provided.
/// </summary>
/// <returns>The configured collection name from <c>_apiSettings.ArchivePatientsRecordingalerts</c>, or the default "archive_patients_recordingalerts" if the setting is null.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=36b86be -->
public override string GetCollectionName()
{
return _apiSettings.ArchivePatientsRecordingalerts ?? "archive_patients_recordingalerts";
@@ -43,6 +46,7 @@ public class RecordingAlertArchiveRepository : MongoRepository<PatientRecordingA
/// Asynchronously inserts a new <see cref="PatientRecordingAlert"/> into the underlying collection.
/// </summary>
/// <param name="patientRecordingAlert">The patient recording alert document to persist.</param>
/// <!-- aidoc:v1 sig=ca2ca36 body=578d26d -->
public override async Task InsertOneAsync(PatientRecordingAlert patientRecordingAlert)
{
await Collection.InsertOneAsync(patientRecordingAlert);
@@ -52,6 +56,7 @@ public class RecordingAlertArchiveRepository : MongoRepository<PatientRecordingA
/// Deletes all <see cref="PatientRecordingAlert"/> records whose <c>Time</c> is earlier than the specified cutoff date.
/// </summary>
/// <param name="date">The cutoff date; records with a time strictly before this value will be removed.</param>
/// <!-- aidoc:v1 sig=63daa66 body=62825db -->
public async Task DeleteBeforeDate(DateTime date)
{
var filter = Builders<PatientRecordingAlert>.Filter.Lt(po => po.Time, date);
@@ -63,6 +68,7 @@ public class RecordingAlertArchiveRepository : MongoRepository<PatientRecordingA
/// </summary>
/// <param name="patientRecordingAlerts">The patient recording alerts to insert into the collection.</param>
/// <returns>The number of patient recording alerts that were inserted.</returns>
/// <!-- aidoc:v1 sig=3442916 body=ee3b5e0 -->
public async Task<long> InsertBatch(IEnumerable<PatientRecordingAlert> patientRecordingAlerts)
{
var writes = new List<WriteModel<PatientRecordingAlert>>();
@@ -14,6 +14,8 @@ namespace adas_core.Infrastructure.Repositories;
/// Provides a MongoDB-backed repository implementation for <see cref="PatientRecordingAlert"/> entities, exposing data access operations defined by the <see cref="IRecordingAlertRepository"/> contract.
/// </summary>
/// <typeparam name="PatientRecordingAlert">The type of recording alert entity managed by the repository.</typeparam>
/// <!-- aidoc-review:v1 severity=medium kind=extra_param
/// "RecordingAlertRepository is a non-generic class that inherits from MongoRepository<PatientRecordingAlert>; the <typeparam name=\"PatientRecordingAlert\"> tag does not belong to this class and should be removed." -->
public class RecordingAlertRepository : MongoRepository<PatientRecordingAlert>, IRecordingAlertRepository
{
private readonly ApiSettings _apiSettings;
@@ -37,6 +39,7 @@ public class RecordingAlertRepository : MongoRepository<PatientRecordingAlert>,
/// Retrieves the collection name for patients recording alerts, returning the configured API setting value or a default fallback when the setting is not available.
/// </summary>
/// <returns>The collection name from <c>_apiSettings.PatientsRecordingAlerts</c>, or the default value "patients_recordingalerts" if the setting is null.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=86753ae -->
public override string GetCollectionName()
{
return _apiSettings.PatientsRecordingAlerts ?? "patients_recordingalerts";
@@ -49,6 +52,7 @@ public class RecordingAlertRepository : MongoRepository<PatientRecordingAlert>,
/// <param name="patientId">The unique identifier of the patient whose observations are being retrieved.</param>
/// <param name="num">The maximum number of recent observations to return per grouped observation name.</param>
/// <returns>A task containing a list of <see cref="PatientRecordingAlert"/> objects representing the aggregated last observations for the patient.</returns>
/// <!-- aidoc:v1 sig=7ba8251 body=28f8b50 -->
public async Task<List<PatientRecordingAlert>> AggregatedPatientLastObservations(ObjectId patientId, int num)
{
var match = new BsonDocument
@@ -132,6 +136,7 @@ public class RecordingAlertRepository : MongoRepository<PatientRecordingAlert>,
/// Deletes a patient recording alert identified by the specified identifier from the underlying collection.
/// </summary>
/// <param name="id">The unique identifier of the patient recording alert to delete.</param>
/// <!-- aidoc:v1 sig=78c6c5d body=e746d33 -->
public new async Task DeleteAsync(ObjectId id)
{
var filter = Builders<PatientRecordingAlert>.Filter.Eq(obs => obs.Id, id);
@@ -143,6 +148,7 @@ public class RecordingAlertRepository : MongoRepository<PatientRecordingAlert>,
/// Inserts a new patient recording alert into the underlying collection asynchronously.
/// </summary>
/// <param name="patientRecordingAlert">The patient recording alert document to be inserted.</param>
/// <!-- aidoc:v1 sig=ca2ca36 body=578d26d -->
public override async Task InsertOneAsync(PatientRecordingAlert patientRecordingAlert)
{
await Collection.InsertOneAsync(patientRecordingAlert);
@@ -153,6 +159,7 @@ public class RecordingAlertRepository : MongoRepository<PatientRecordingAlert>,
/// </summary>
/// <param name="name">The name of the patient recording alert used to match the document for deletion.</param>
/// <param name="retentionPolicyValue">The retention period in days; the cutoff time is calculated as UTC now minus this number of days.</param>
/// <!-- aidoc:v1 sig=f57ae81 body=38e47b8 -->
public async Task DeleteOlderDaysAsync(string name, int retentionPolicyValue)
{
var filterBuilder = Builders<PatientRecordingAlert>.Filter;
@@ -169,6 +176,7 @@ public class RecordingAlertRepository : MongoRepository<PatientRecordingAlert>,
/// Deletes all patient recording alerts associated with the specified patient identifier.
/// </summary>
/// <param name="patientId">The unique identifier of the patient whose recording alerts will be removed.</param>
/// <!-- aidoc:v1 sig=4776e51 body=7caf6e5 -->
public async Task DeleteByPatientId(ObjectId patientId)
{
var filter = Builders<PatientRecordingAlert>.Filter.Eq(po => po.PatientId, patientId);
@@ -181,6 +189,7 @@ public class RecordingAlertRepository : MongoRepository<PatientRecordingAlert>,
/// </summary>
/// <param name="name">The name used to filter the alerts subject to the retention policy.</param>
/// <param name="retentionPolicyValue">The number of most recent records to retain; any additional older records will be deleted.</param>
/// <!-- aidoc:v1 sig=c937e38 body=7d9fe21 -->
public async Task DeleteOlderNumberAsync(string name, int retentionPolicyValue)
{
var filterBuilder = Builders<PatientRecordingAlert>.Filter;
@@ -211,6 +220,7 @@ public class RecordingAlertRepository : MongoRepository<PatientRecordingAlert>,
/// </summary>
/// <param name="patientId">The unique identifier of the patient whose recording alerts should be retrieved.</param>
/// <returns>A task representing the asynchronous operation, containing a cursor over the matching patient recording alerts.</returns>
/// <!-- aidoc:v1 sig=e63f91e body=0dc65bb -->
public async Task<IAsyncCursor<PatientRecordingAlert>> FindByPatientIdAsync(ObjectId patientId)
{
var filter = Builders<PatientRecordingAlert>.Filter.Eq(ob => ob.PatientId, patientId);
@@ -225,6 +235,7 @@ public class RecordingAlertRepository : MongoRepository<PatientRecordingAlert>,
/// <param name="name">The name of the observation used to filter the results.</param>
/// <param name="num">The maximum number of observations to return. Defaults to 2.</param>
/// <returns>A list of <see cref="PatientRecordingAlert"/> entries containing the latest matching observations for the patient.</returns>
/// <!-- aidoc:v1 sig=47628d4 body=4ebb0f9 -->
public async Task<List<PatientRecordingAlert>> FindLastObservations(ObjectId patientId, string name, int num = 2)
{
var filterBuilder = Builders<PatientRecordingAlert>.Filter;
@@ -256,6 +267,7 @@ public class RecordingAlertRepository : MongoRepository<PatientRecordingAlert>,
/// <param name="nameId">The identifier of the field or collection used to target the records to update.</param>
/// <param name="id">The new <see cref="ObjectId"/> value to assign to the matched records.</param>
/// <param name="oldId">The existing <see cref="ObjectId"/> value to be replaced.</param>
/// <!-- aidoc:v1 sig=72ce1ca body=b9b81e9 -->
public async Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId)
{
await UpdateManyObjectIdAsync(nameId, id, oldId);
@@ -264,6 +276,7 @@ public class RecordingAlertRepository : MongoRepository<PatientRecordingAlert>,
/// <summary>
/// Creates MongoDB indexes for the PatientRecordingAlert collection, including a non-unique background index on the patientid field to optimize queries by patient.
/// </summary>
/// <!-- aidoc:v1 sig=4955da2 body=04093f9 -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions { Background = true, Unique = false };
@@ -17,6 +17,8 @@ namespace adas_core.Infrastructure.Repositories;
/// </summary>
/// <typeparam name="Relay">The type of the entity managed by the repository.</typeparam>
/// <remarks>This class combines a concrete MongoDB repository implementation with a domain-specific interface, enabling standardized persistence operations for relay entities.</remarks>
/// <!-- aidoc-review:v1 severity=high kind=extra_param
/// "RelayRepository is not a generic class (declared as 'public class RelayRepository : MongoRepository<Relay>, IRelayRepository'), so the <typeparam name='Relay'> tag is invalid. Relay is a concrete type used as the type argument to the base class, not a type parameter of RelayRepository." -->
public class RelayRepository : MongoRepository<Relay>, IRelayRepository
{
private readonly ApiSettings _apiSettings;
@@ -38,6 +40,7 @@ public class RelayRepository : MongoRepository<Relay>, IRelayRepository
/// Retrieves the collection name for relays from the API settings configuration.
/// </summary>
/// <returns>The configured relays collection name as specified in the API settings.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=c6df698 -->
public override string GetCollectionName()
{
return _apiSettings.Relays;
@@ -48,6 +51,7 @@ public class RelayRepository : MongoRepository<Relay>, IRelayRepository
/// </summary>
/// <param name="relayId">The unique identifier of the relay to look up.</param>
/// <returns>The matching <see cref="Relay"/>, or <c>null</c> if no document matches the identifier or the query fails.</returns>
/// <!-- aidoc:v1 sig=3807664 body=f06b9f2 -->
public async Task<Relay?> GetById(ObjectId relayId)
{
try
@@ -69,6 +73,7 @@ public class RelayRepository : MongoRepository<Relay>, IRelayRepository
/// <param name="configurationRelayList">The collection of relay identifiers used to filter relays by their Id field.</param>
/// <param name="type">The relay type used as an equality filter on the Type field.</param>
/// <returns>A list of <see cref="Relay"/> instances matching both the identifier and type filters; an empty list is returned when no relays match.</returns>
/// <!-- aidoc:v1 sig=ef9043b body=3a8764d -->
public List<Relay> GetRelayByTypeInList(List<ObjectId> configurationRelayList, RelayEnum.Type type)
{
var filterBuilder = Builders<Relay>.Filter;
@@ -86,6 +91,7 @@ public class RelayRepository : MongoRepository<Relay>, IRelayRepository
/// </summary>
/// <param name="configurationRelayList">The collection of <see cref="ObjectId"/> values used to match relays by their <c>Id</c> field.</param>
/// <returns>A <see cref="List{Relay}"/> containing the relays whose identifiers are found in <paramref name="configurationRelayList"/>; an empty list is returned when no matching relays exist.</returns>
/// <!-- aidoc:v1 sig=262306c body=ab06cc9 -->
public List<Relay> GetRelayInList(List<ObjectId> configurationRelayList)
{
var filterBuilder = Builders<Relay>.Filter;
@@ -102,6 +108,7 @@ public class RelayRepository : MongoRepository<Relay>, IRelayRepository
/// </summary>
/// <param name="filter">The pagination criteria containing the optional text filter applied against the relay name.</param>
/// <returns>A fluent find query for <see cref="Relay"/> entities, ordered by relay name in ascending order, ready for further pagination.</returns>
/// <!-- aidoc:v1 sig=6da9abe body=35a5fce -->
public IFindFluent<Relay, Relay> GetPaginatedRelays(PaginationFilter filter)
{
var filterBuilder = Builders<Relay>.Filter;
@@ -132,6 +139,7 @@ public class RelayRepository : MongoRepository<Relay>, IRelayRepository
/// </summary>
/// <param name="request">The relay entity to insert into the collection.</param>
/// <returns>The inserted relay retrieved by its identifier, or <c>null</c> if the insertion fails.</returns>
/// <!-- aidoc:v1 sig=79b3c83 body=60b6b6c -->
public async Task<Relay?> InsertOneRelayAsync(Relay request)
{
try
@@ -154,6 +162,7 @@ public class RelayRepository : MongoRepository<Relay>, IRelayRepository
/// <param name="objectId">The unique identifier of the relay document to update in the collection.</param>
/// <param name="relay">The relay instance containing the new values to apply to the existing document.</param>
/// <returns>A task that represents the asynchronous operation, containing the updated <see cref="Relay"/> after the update, or <c>null</c> if no matching document was found.</returns>
/// <!-- aidoc:v1 sig=2ca072d body=5a785d8 -->
public async Task<Relay?> UpdateRelayAsync(ObjectId objectId, Relay relay)
{
var filter = Builders<Relay>.Filter.Eq("_id", objectId);
@@ -176,6 +185,7 @@ public class RelayRepository : MongoRepository<Relay>, IRelayRepository
/// </summary>
/// <param name="requestRelayName">The name of the relay to look up. May be <c>null</c>, in which case the query matches relays with a null name.</param>
/// <returns>A <see cref="Task{TResult}"/> containing the matching <see cref="Relay"/>, or <c>null</c> if no relay with the specified name is found.</returns>
/// <!-- aidoc:v1 sig=22f1a02 body=1a92d9a -->
public async Task<Relay?> GetByName(string? requestRelayName)
{
var filterBuilder = Builders<Relay>.Filter;
@@ -191,6 +201,7 @@ public class RelayRepository : MongoRepository<Relay>, IRelayRepository
/// <param name="filters">The list of filter definitions to combine; when empty, an empty filter is used to match all documents.</param>
/// <param name="sort">The sort definition applied to the query results.</param>
/// <returns>An <see cref="IFindFluent{TDocument, TProjection}"/> representing the filtered and sorted Relay query.</returns>
/// <!-- aidoc:v1 sig=e3578fc body=a377885 -->
private IFindFluent<Relay, Relay> CreateFindFluent(List<FilterDefinition<Relay>> filters, SortDefinition<Relay> sort)
{
var combinedFilter = filters.Any()
@@ -14,6 +14,8 @@ namespace adas_core.Infrastructure.Repositories;
/// implementing the contract defined by <see cref="ISectionRepository"/>.
/// </summary>
/// <typeparam name="Section">The type of the section entity managed by this repository.</typeparam>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The documentation uses <typeparamref name='Section'/> in the summary and declares a <typeparam name='Section'> element on a non-generic class, misrepresenting the class as having a type parameter when Section is only a type argument to the generic base class MongoRepository<Section>." -->
public class SectionRepository : MongoRepository<Section>, ISectionRepository
{
private readonly ApiSettings _apiSettings;
@@ -38,6 +40,7 @@ public class SectionRepository : MongoRepository<Section>, ISectionRepository
/// Gets the configuration sections collection name from the API settings, falling back to a default value when not configured.
/// </summary>
/// <returns>The configured collection name, or "config_sections" if <c>_apiSettings.ConfigSections</c> is null.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=538109a -->
public override string GetCollectionName()
{
return _apiSettings.ConfigSections ?? "config_sections";
@@ -47,6 +50,7 @@ public class SectionRepository : MongoRepository<Section>, ISectionRepository
/// Retrieves all <see cref="Section"/> documents from the underlying collection by querying with an empty filter.
/// </summary>
/// <returns>A task that represents the asynchronous operation, containing a list of all <see cref="Section"/> documents found in the collection.</returns>
/// <!-- aidoc:v1 sig=c63d5ab body=5e7c572 -->
public async Task<List<Section>> GetAll()
{
var result = await Collection.FindAsync(Builders<Section>.Filter.Empty);
@@ -59,6 +63,7 @@ public class SectionRepository : MongoRepository<Section>, ISectionRepository
/// </summary>
/// <param name="section">The section title used to look up the matching <see cref="Section"/>.</param>
/// <returns>The first matching <see cref="Section"/>, or <c>null</c> if no section with the given title is found.</returns>
/// <!-- aidoc:v1 sig=657d14e body=7fd0ba3 -->
public async Task<Section?> FindBySection(string section)
{
var result = await Collection.FindAsync(Builders<Section>.Filter.Eq(x => x.SectionTitle, section));
@@ -71,6 +76,7 @@ public class SectionRepository : MongoRepository<Section>, ISectionRepository
/// </summary>
/// <param name="pointOfCare">The point of care identifier used to filter the sections.</param>
/// <returns>The first matching <see cref="Section"/>, or <c>null</c> if no section is found.</returns>
/// <!-- aidoc:v1 sig=a604321 body=7d830b2 -->
public async Task<Section?> FindByPointOfCare(string pointOfCare)
{
var result = await Collection.FindAsync(Builders<Section>.Filter.Eq(x => x.PointOfCare, pointOfCare));
@@ -84,6 +90,7 @@ public class SectionRepository : MongoRepository<Section>, ISectionRepository
/// </summary>
/// <param name="id">The unique identifier of the section to retrieve.</param>
/// <returns>A task containing the matching <see cref="Section"/> if found; otherwise, <c>null</c>.</returns>
/// <!-- aidoc:v1 sig=b74d29e body=35f3782 -->
public async Task<Section?> FindById(string id)
{
var result = await Collection.FindAsync(Builders<Section>.Filter.Eq(x => x.Id, id));
@@ -96,6 +103,7 @@ public class SectionRepository : MongoRepository<Section>, ISectionRepository
/// </summary>
/// <param name="id">The identifier of the section to locate.</param>
/// <returns>A <see cref="Section"/> instance if a document with the given identifier exists; otherwise, <c>null</c>.</returns>
/// <!-- aidoc:v1 sig=d503cfd body=43632c9 -->
public async Task<Section?> FindById(object id)
{
var result = await Collection.FindAsync(Builders<Section>.Filter.Eq(x => x._id, id));
@@ -109,6 +117,8 @@ public class SectionRepository : MongoRepository<Section>, ISectionRepository
/// </summary>
/// <param name="location">The patient location containing the unit name and bed used to locate the corresponding sections.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains a list of sections matching the provided patient location; an empty list is returned when no matching sections are found.</returns>
/// <!-- aidoc-review:v1 severity=low kind=wrong_summary
/// "The summary refers to 'active sections,' but the code only checks `box.IsActive`; the sections themselves are not filtered by any active state." -->
public async Task<List<Section>> FindByLocation(PatientLocation location)
{
//can not filter to Collection the where condition, it throws System.InvalidOperationException: '{}.pointOfCare is not supported.'
@@ -128,6 +138,7 @@ public class SectionRepository : MongoRepository<Section>, ISectionRepository
/// </summary>
/// <param name="section">The section to insert into the collection.</param>
/// <returns>The inserted <see cref="Section"/> on success, or <c>null</c> if the operation fails.</returns>
/// <!-- aidoc:v1 sig=6e6c338 body=c888f94 -->
public async Task<Section?> InsertOneSection(Section section)
{
try
@@ -151,6 +162,7 @@ public class SectionRepository : MongoRepository<Section>, ISectionRepository
/// </summary>
/// <param name="section">The section containing the identifier of the record to update and the new field values to persist.</param>
/// <returns>The updated <see cref="Section"/> as it appears after the update, or <see langword="null"/> if no matching record was found.</returns>
/// <!-- aidoc:v1 sig=21df1de body=d447f33 -->
public async Task<Section?> UpdateSection(Section section)
{
var filter = Builders<Section>.Filter.Eq("Id", section.Id);
@@ -10,6 +10,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Represents a MongoDB repository for <see cref="ServiceConfig"/> entities, implementing the <see cref="IServiceConfigRepository"/> contract to provide data access operations.
/// </summary>
/// <!-- aidoc:v1 sig=1c7de6e -->
public class ServiceConfigRepository : MongoRepository<ServiceConfig>, IServiceConfigRepository
{
private readonly ApiSettings _apiSettings;
@@ -33,6 +34,7 @@ public class ServiceConfigRepository : MongoRepository<ServiceConfig>, IServiceC
/// Retrieves the service configuration collection name from API settings, falling back to the default "service_config" when no value is configured.
/// </summary>
/// <returns>The configured service collection name, or the default "service_config" when the API setting is null.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=8cab977 -->
public override string GetCollectionName()
{
return _apiSettings.ServiceConfig ?? "service_config";
@@ -44,6 +46,7 @@ public class ServiceConfigRepository : MongoRepository<ServiceConfig>, IServiceC
/// </summary>
/// <param name="id">The string identifier used to look up the service configuration.</param>
/// <returns>A task that represents the asynchronous operation, containing the matching <see cref="ServiceConfig"/> or <c>null</c> if not found.</returns>
/// <!-- aidoc:v1 sig=ea95853 body=ad0ec9c -->
public async Task<ServiceConfig?> FindById(string id)
{
var result = await Collection.FindAsync(Builders<ServiceConfig>.Filter.Eq(x => x.StrId, id));
@@ -56,6 +59,7 @@ public class ServiceConfigRepository : MongoRepository<ServiceConfig>, IServiceC
/// </summary>
/// <param name="oid">The <see cref="ObjectId"/> of the <see cref="ServiceConfig"/> to locate.</param>
/// <returns>A <see cref="ServiceConfig"/> instance if a document with the given identifier is found; otherwise, <see langword="null"/>.</returns>
/// <!-- aidoc:v1 sig=66de090 body=218bdce -->
public async Task<ServiceConfig?> FindById(ObjectId oid)
{
var result = await Collection.FindAsync(Builders<ServiceConfig>.Filter.Eq(x => x.Id, oid));
@@ -11,6 +11,7 @@ namespace adas_core.Infrastructure.Repositories;
/// Provides a MongoDB-backed repository for persisting and retrieving archived patient treatment records.
/// Inherits from <see cref="MongoRepository{PatientTreatment}"/> and implements the <see cref="ITreatmentArchiveRepository"/> contract.
/// </summary>
/// <!-- aidoc:v1 sig=00919c4 -->
public class TreatmentArchiveRepository : MongoRepository<PatientTreatment>, ITreatmentArchiveRepository
{
private readonly ApiSettings _apiSettings;
@@ -34,6 +35,7 @@ public class TreatmentArchiveRepository : MongoRepository<PatientTreatment>, ITr
/// Asynchronously inserts a single <see cref="PatientTreatment"/> document into the collection.
/// </summary>
/// <param name="patientTreatment">The patient treatment entity to persist.</param>
/// <!-- aidoc:v1 sig=817004e body=78ae787 -->
public override async Task InsertOneAsync(PatientTreatment patientTreatment)
{
await Collection.InsertOneAsync(patientTreatment);
@@ -43,6 +45,7 @@ public class TreatmentArchiveRepository : MongoRepository<PatientTreatment>, ITr
/// Deletes all patient treatments whose order time is before the specified date.
/// </summary>
/// <param name="date">The cutoff date; treatments with an order time earlier than this are removed.</param>
/// <!-- aidoc:v1 sig=63daa66 body=62a2131 -->
public async Task DeleteBeforeDate(DateTime date)
{
var filter = Builders<PatientTreatment>.Filter.Lt(po => po.OrderTime, date);
@@ -54,6 +57,7 @@ public class TreatmentArchiveRepository : MongoRepository<PatientTreatment>, ITr
/// </summary>
/// <param name="treatments">The collection of patient treatment records to insert into the database.</param>
/// <returns>The total count of patient treatment records inserted by the bulk write operation.</returns>
/// <!-- aidoc:v1 sig=5327a55 body=14e0e13 -->
public async Task<long> InsertBatch(IEnumerable<PatientTreatment> treatments)
{
var writes = new List<WriteModel<PatientTreatment>>();
@@ -69,6 +73,7 @@ public class TreatmentArchiveRepository : MongoRepository<PatientTreatment>, ITr
/// </summary>
/// <param name="patientId">The unique identifier of the patient whose treatment records are to be retrieved.</param>
/// <returns>A task that represents the asynchronous operation, containing a list of <see cref="PatientTreatment"/> records matching the specified patient.</returns>
/// <!-- aidoc:v1 sig=26634ec body=cdc309e -->
public async Task<List<PatientTreatment>> FindAllFromPatient(ObjectId patientId)
{
var filter = Builders<PatientTreatment>.Filter.Eq(t => t.PatientId, patientId);
@@ -81,6 +86,7 @@ public class TreatmentArchiveRepository : MongoRepository<PatientTreatment>, ITr
/// Retrieves the collection name for archive patients treatments, falling back to the default "archive_patients_treatments" value when the API settings do not specify one.
/// </summary>
/// <returns>The configured collection name from the API settings, or the default "archive_patients_treatments" if the setting is null.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=a88c4fb -->
public override string GetCollectionName()
{
return _apiSettings.ArchivePatientsTreatments ?? "archive_patients_treatments";
@@ -14,6 +14,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Represents a MongoDB-backed repository for <see cref="PatientTreatment"/> entities, inheriting common data access functionality from <see cref="MongoRepository{T}"/> and implementing the <see cref="ITreatmentRepository"/> contract.
/// </summary>
/// <!-- aidoc:v1 sig=ff348dc -->
public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatmentRepository
{
private readonly ApiSettings _apiSettings;
@@ -37,6 +38,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// Retrieves the collection name for patients treatments, using the value configured in API settings or falling back to the default "patients_treatments" when the setting is not specified.
/// </summary>
/// <returns>The configured patients treatments collection name, or "patients_treatments" if no setting is defined.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=9f934d7 -->
public override string GetCollectionName()
{
return _apiSettings.PatientsTreatments ?? "patients_treatments";
@@ -47,6 +49,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// </summary>
/// <param name="patientId">The unique identifier of the patient whose treatments are being queried.</param>
/// <returns>A collection of <see cref="PatientTreatment"/> records matching the specified patient identifier.</returns>
/// <!-- aidoc:v1 sig=378ba8a body=7965a74 -->
public async Task<IEnumerable<PatientTreatment>> GetByPatientId(ObjectId patientId)
{
var filter = Builders<PatientTreatment>.Filter.Eq(ob => ob.PatientId, patientId);
@@ -59,6 +62,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// </summary>
/// <param name="id">The unique identifier of the patient treatment to locate.</param>
/// <returns>An asynchronous cursor containing the patient treatment matching the provided identifier.</returns>
/// <!-- aidoc:v1 sig=9df111b body=2d38c53 -->
public async Task<IAsyncCursor<PatientTreatment>> GetById(ObjectId id)
{
var filter = Builders<PatientTreatment>.Filter.Eq(ob => ob.Id, id);
@@ -70,6 +74,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// Inserts a patient treatment record, defaulting the order time to the current UTC time when it is not already set.
/// </summary>
/// <param name="treatment">The patient treatment to insert.</param>
/// <!-- aidoc:v1 sig=e510e9e body=e2feaed -->
public override async Task InsertOneAsync(PatientTreatment treatment)
{
treatment.OrderTime ??= DateTime.UtcNow;
@@ -80,6 +85,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// Deletes a patient treatment record from the database by its unique identifier.
/// </summary>
/// <param name="id">The unique identifier of the patient treatment to remove.</param>
/// <!-- aidoc:v1 sig=78c6c5d body=ffccab9 -->
public new async Task DeleteAsync(ObjectId id)
{
var filter = Builders<PatientTreatment>.Filter.Eq(ob => ob.Id, id);
@@ -92,6 +98,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// </summary>
/// <param name="patientId">The unique ObjectId of the patient whose treatment records should be returned.</param>
/// <returns>An <see cref="IAsyncCursor{TDocument}"/> of <see cref="PatientTreatment"/> containing the matching treatment records.</returns>
/// <!-- aidoc:v1 sig=2560a5d body=b55629b -->
public async Task<IAsyncCursor<PatientTreatment>> FindByPatientIdAsync(ObjectId patientId)
{
var filter = Builders<PatientTreatment>.Filter.Eq(ob => ob.PatientId, patientId);
@@ -105,6 +112,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// </summary>
/// <param name="patientId">The identifier of the patient whose treatment records should be removed.</param>
/// <returns>A task that resolves to <c>true</c> on successful deletion, or <c>false</c> if the operation failed due to an exception.</returns>
/// <!-- aidoc:v1 sig=792a636 body=a3d746d -->
public async Task<bool> DeleteByPatientId(ObjectId patientId)
{
try
@@ -126,6 +134,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// </summary>
/// <param name="treatment">The patient treatment entity containing the updated information, identified by its <c>Id</c>.</param>
/// <returns><c>true</c> if the update succeeds; otherwise, <c>false</c> if an exception occurs during the operation.</returns>
/// <!-- aidoc:v1 sig=c17e7d4 body=21b1397 -->
public async Task<bool> Update(PatientTreatment treatment)
{
try
@@ -145,6 +154,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// </summary>
/// <param name="patientId">The unique identifier of the patient whose bolus treatments are being queried.</param>
/// <returns>A task that represents the asynchronous operation, containing a list of <see cref="PatientTreatment"/> documents matching the patient and having a non-empty <c>RequestedGiveCodesStatus</c>.</returns>
/// <!-- aidoc:v1 sig=cf3ed2a body=b450746 -->
public async Task<List<PatientTreatment>> FindBolusTreatments(ObjectId patientId)
{
var builder = Builders<PatientTreatment>.Filter;
@@ -166,6 +176,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// <param name="patientId">The identifier of the patient whose treatments will be searched.</param>
/// <param name="order">The entity identifier of the placer order used to match treatments.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the list of matching <see cref="PatientTreatment"/> entries.</returns>
/// <!-- aidoc:v1 sig=3821694 body=b830b97 -->
public async Task<List<PatientTreatment>> GetActiveTreatmentsByPatientIdAndOrder(ObjectId patientId, string order)
{
var builder = Builders<PatientTreatment>.Filter;
@@ -193,6 +204,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// <param name="nameId">The name of the field or relationship whose object identifier should be updated.</param>
/// <param name="id">The new object identifier to replace the old one with.</param>
/// <param name="oldId">The existing object identifier that should be replaced.</param>
/// <!-- aidoc:v1 sig=72ce1ca body=b9b81e9 -->
public async Task UpdateManyObjectId(string nameId, ObjectId id, ObjectId oldId)
{
await UpdateManyObjectIdAsync(nameId, id, oldId);
@@ -203,6 +215,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// </summary>
/// <param name="patientId">The unique <see cref="ObjectId"/> of the patient whose treatments are being queried.</param>
/// <returns>A task that represents the asynchronous operation, containing an <see cref="IEnumerable{PatientTreatment}"/> with the matching treatment records. Returns an empty sequence if no treatments are found.</returns>
/// <!-- aidoc:v1 sig=1aafccf body=7965a74 -->
public async Task<IEnumerable<PatientTreatment>> FindByPatientId(ObjectId patientId)
{
var filter = Builders<PatientTreatment>.Filter.Eq(ob => ob.PatientId, patientId);
@@ -252,6 +265,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// <summary>
/// Ensures the required MongoDB indexes exist for the <see cref="PatientTreatment"/> collection, creating a non-unique background index on the <c>patientid</c> field to optimize query performance without blocking other database operations.
/// </summary>
/// <!-- aidoc:v1 sig=4955da2 body=7b72bb5 -->
public override async Task CreateIndexes()
{
var options = new CreateIndexOptions { Background = true, Unique = false };
@@ -268,6 +282,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// </summary>
/// <param name="filters">The collection of filter definitions to which the active treatment criteria will be appended.</param>
/// <param name="filterBuilder">The builder used to construct the individual filter conditions combined for the active treatment logic.</param>
/// <!-- aidoc:v1 sig=52a33ae body=7b0cd33 -->
private static void AddActiveTreatmentFilters(List<FilterDefinition<PatientTreatment>> filters,
FilterDefinitionBuilder<PatientTreatment> filterBuilder)
{
@@ -311,6 +326,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// <param name="filters">The list of filter definitions to which the start and end time filters will be added.</param>
/// <param name="filter">The pagination filter containing the optional start and end date values from the request.</param>
/// <param name="filterBuilder">The filter definition builder used to construct the MongoDB filter expressions.</param>
/// <!-- aidoc:v1 sig=b6dabce body=a3424c3 -->
private void AddDefaultTimeFilters(List<FilterDefinition<PatientTreatment>> filters, PaginationFilter filter,
FilterDefinitionBuilder<PatientTreatment> filterBuilder)
{
@@ -336,6 +352,7 @@ public class TreatmentRepository : MongoRepository<PatientTreatment>, ITreatment
/// <param name="filters">The list of filter definitions to combine; if empty, an empty filter is used instead.</param>
/// <param name="sort">The sort definition to apply to the query results.</param>
/// <returns>An <see cref="IFindFluent{PatientTreatment, PatientTreatment}"/> representing the configured find query with the combined filter and sort applied.</returns>
/// <!-- aidoc:v1 sig=45f2edf body=8cd8049 -->
private IFindFluent<PatientTreatment, PatientTreatment> CreateFindFluent(
List<FilterDefinition<PatientTreatment>> filters, SortDefinition<PatientTreatment> sort)
{
@@ -16,6 +16,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <summary>
/// Represents a MongoDB-backed repository for <see cref="Unit"/> entities, inheriting persistence functionality from <see cref="MongoRepository{Unit}"/> and implementing the <see cref="IUnitRepository"/> contract.
/// </summary>
/// <!-- aidoc:v1 sig=2997ff1 -->
public class UnitRepository : MongoRepository<Unit>, IUnitRepository
{
#region Properties
@@ -51,6 +52,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// </summary>
/// <param name="unit">The <see cref="Unit"/> to be inserted into the collection.</param>
/// <returns>The inserted <see cref="Unit"/> as returned by the lookup by identifier, or <c>null</c> if an exception occurred during insertion.</returns>
/// <!-- aidoc:v1 sig=46b66ca body=55b385e -->
public async Task<Unit?> InsertOneUnit(Unit unit)
{
try
@@ -75,6 +77,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// Gets the collection name for units, returning the configured value from API settings or falling back to the default "units" when not specified.
/// </summary>
/// <returns>The collection name for units, or "units" if no custom value is configured in the API settings.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=48f375a -->
public override string GetCollectionName()
{
return _apiSettings.Units ?? "units";
@@ -94,6 +97,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// </summary>
/// <param name="id">The identifier of the <see cref="Unit"/> to locate.</param>
/// <returns>A <see cref="Unit"/> instance if a match is found; otherwise, <see langword="null"/>.</returns>
/// <!-- aidoc:v1 sig=2cb132e body=4a4ce42 -->
public async Task<Unit?> FindById(object id)
{
var result = await Collection.FindAsync(Builders<Unit>.Filter.Eq(x => x.Id, id));
@@ -106,6 +110,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// <param name="id">The unique identifier of the unit to look up.</param>
/// <returns>A task that represents the asynchronous operation. The task result contains the matching <see cref="Unit"/>, or <c>null</c> if no unit is found with the specified identifier.</returns>
/// <exception cref="NotImplementedException">The method is not yet implemented.</exception>
/// <!-- aidoc:v1 sig=b1966a7 body=bfa6f2f -->
public Task<Unit?> FindById(string id)
{
throw new NotImplementedException();
@@ -144,6 +149,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// </summary>
/// <param name="id">The <see cref="ObjectId"/> of the master list to search for across the unit's list reference fields.</param>
/// <returns>A task that yields an <see cref="IEnumerable{Unit}"/> containing the matching units, or an empty list if no matches are found or an error occurs.</returns>
/// <!-- aidoc:v1 sig=be856f1 body=b563580 -->
public async Task<IEnumerable<Unit>> FindByMasterListId(ObjectId id)
{
try
@@ -196,6 +202,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// <param name="id">The <see cref="ObjectId"/> of the master list used to match units.</param>
/// <param name="masterListType">The type of master list, which determines the property name used in the filter.</param>
/// <returns>The total number of <see cref="Unit"/> documents that match the filter.</returns>
/// <!-- aidoc:v1 sig=22d5ac5 body=8e9b4d7 -->
public async Task<long> CountUnitsByMasterListId(ObjectId id, MasterListType masterListType)
{
var propertyName = $"{masterListType}Id";
@@ -209,6 +216,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// </summary>
/// <param name="unitName">The name of the unit to look up using an exact equality match.</param>
/// <returns>A <see cref="Task{Unit?}"/> containing the matching <see cref="Unit"/> if found; otherwise, <c>null</c>.</returns>
/// <!-- aidoc:v1 sig=12e24aa body=ec93cdf -->
public async Task<Unit?> FindByName(string unitName)
{
var result = await Collection.FindAsync(Builders<Unit>.Filter.Eq(x => x.Name, unitName));
@@ -241,6 +249,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// Asynchronously retrieves all <see cref="Unit"/> records from the underlying collection.
/// </summary>
/// <returns>A task that represents the asynchronous operation, containing a list of all <see cref="Unit"/> documents found in the collection.</returns>
/// <!-- aidoc:v1 sig=b1cb9b5 body=bc87eac -->
public async Task<List<Unit>> GetAll()
{
var result = await Collection.FindAsync(Builders<Unit>.Filter.Empty);
@@ -254,6 +263,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// </summary>
/// <param name="filter">The pagination filter containing the optional text search criteria used to narrow the result set.</param>
/// <returns>An <see cref="IFindFluent{Unit, Unit}"/> representing the sorted and filtered query of units; if no filter request is supplied, an unfiltered query sorted by title is returned.</returns>
/// <!-- aidoc:v1 sig=9b2e0d7 body=ec22e2e -->
public IFindFluent<Unit, Unit> GetPaginatedUnits(PaginationFilter filter)
{
var filterBuilder = Builders<Unit>.Filter;
@@ -286,6 +296,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// <param name="filters">The list of filter definitions to combine with a logical AND; if empty, no filtering is applied.</param>
/// <param name="sort">The sort definition to apply to the query results.</param>
/// <returns>A fluent find interface for <see cref="Unit"/> that can be further chained to project, limit, or execute the query.</returns>
/// <!-- aidoc:v1 sig=ef193db body=8638b4d -->
private IFindFluent<Unit, Unit> CreateFindFluent(List<FilterDefinition<Unit>> filters, SortDefinition<Unit> sort)
{
var combinedFilter = filters.Any()
@@ -304,6 +315,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// </summary>
/// <param name="unit">The unit containing the identifier and the new field values to be persisted.</param>
/// <returns>The updated unit after the operation, or null if no document matched the filter.</returns>
/// <!-- aidoc:v1 sig=2e95c1d body=72db12f -->
public async Task<Unit?> UpdateUnit(Unit unit)
{
var filter = Builders<Unit>.Filter.Eq("_id", unit.Id);
@@ -343,6 +355,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// <param name="name">The new name to assign to the unit.</param>
/// <param name="title">The new title to assign to the unit.</param>
/// <returns>The updated <see cref="Unit"/> after the modification, or <c>null</c> if no matching unit was found.</returns>
/// <!-- aidoc:v1 sig=cb1f7cc body=764f8fb -->
public async Task<Unit?> UpdateUnitInfo(ObjectId unitId, string name, string title)
{
var filter = Builders<Unit>.Filter.Eq("_id", unitId);
@@ -364,6 +377,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// </summary>
/// <param name="updateUnitListDto">The DTO containing the target <c>UnitId</c> and the collection of master list entries to update.</param>
/// <returns>The updated <see cref="Unit"/> after the modifications, or <c>null</c> if no updates were performed.</returns>
/// <!-- aidoc:v1 sig=303c1f2 body=9b5590e -->
public async Task<Unit?> UpdateUnitMasterList(UpdateUnitIdListDto updateUnitListDto)
{
var filter = Builders<Unit>.Filter.Eq("_id", updateUnitListDto.UnitId);
@@ -459,6 +473,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// <param name="unitIdParsed">The <see cref="ObjectId"/> of the unit whose configuration will be updated.</param>
/// <param name="unitConfiguration">The new <see cref="UnitConfiguration"/> to apply to the unit.</param>
/// <returns>A task that resolves to <c>true</c> when the update modified a document; otherwise <c>false</c> (including when the operation throws and the error is logged).</returns>
/// <!-- aidoc:v1 sig=0ae31e8 body=dd19aa3 -->
public async Task<bool> UpdateConfiguration(ObjectId unitIdParsed, UnitConfiguration unitConfiguration)
{
var filter = Builders<Unit>.Filter.Eq("_id", unitIdParsed);
@@ -485,6 +500,7 @@ public class UnitRepository : MongoRepository<Unit>, IUnitRepository
/// </summary>
/// <param name="id">The identifier of the unit to delete.</param>
/// <returns>The deleted <see cref="Unit"/> if found and removed; otherwise, <c>null</c> when an error occurs.</returns>
/// <!-- aidoc:v1 sig=07e45cd body=5ae0f5c -->
public new async Task<Unit?> DeleteAsync(ObjectId id)
{
var filter = Builders<Unit>.Filter.Eq(unit => unit.Id, id);
@@ -16,6 +16,7 @@ namespace adas_core.Infrastructure.Repositories;
/// <remarks>
/// Inherits core data access functionality from <see cref="MongoRepository{User}"/> and implements the <see cref="IUserRepository"/> contract.
/// </remarks>
/// <!-- aidoc:v1 sig=7f8031c -->
public class UserRepository : MongoRepository<User>, IUserRepository
{
private readonly ApiSettings _apiSettings;
@@ -37,6 +38,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// Retrieves the API collection name for users from the configured API settings.
/// </summary>
/// <returns>The configured name of the users collection.</returns>
/// <!-- aidoc:v1 sig=94e22ff body=f29d25a -->
public override string GetCollectionName()
{
return _apiSettings.Users;
@@ -49,6 +51,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// <param name="username">The username to look up in the collection.</param>
/// <param name="password">The password that must match the stored value for the user to be returned.</param>
/// <returns>A <see cref="User"/> instance when a matching record is found; otherwise, <c>null</c>.</returns>
/// <!-- aidoc:v1 sig=be4ac11 body=ac01c98 -->
public async Task<User?> GetUser(string username, string password)
{
var filter = Builders<User>
@@ -63,6 +66,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// </summary>
/// <param name="id">The <see cref="ObjectId"/> of the user to look up.</param>
/// <returns>A <see cref="User"/> instance if a matching document exists; otherwise, <c>null</c>.</returns>
/// <!-- aidoc:v1 sig=9cec1a5 body=78ead0f -->
public async Task<User?> GetById(ObjectId id)
{
var filter = Builders<User>
@@ -77,6 +81,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// </summary>
/// <param name="name">The username used to look up the user.</param>
/// <returns>A <see cref="User"/> instance if a match is found; otherwise, <c>null</c>.</returns>
/// <!-- aidoc:v1 sig=c23232a body=1f6c5cb -->
public async Task<User?> GetByUserName(string name)
{
var filter = Builders<User>
@@ -90,6 +95,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// </summary>
/// <param name="name">The username used to match the user document in the collection.</param>
/// <returns>A <see cref="Task{TResult}"/> that yields the matching <see cref="User"/> with its authorizations and resolved role, or <c>null</c> if no user is found.</returns>
/// <!-- aidoc:v1 sig=31b518d body=72882f6 -->
public async Task<User?> GetByUserAndAuthoritesName(string name)
{
var matchStage = new BsonDocument("$match", new BsonDocument("userName", name));
@@ -137,6 +143,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// </summary>
/// <param name="name">The name of the user to look up.</param>
/// <returns>A <see cref="User"/> instance if a match is found; otherwise, null.</returns>
/// <!-- aidoc:v1 sig=ccb9033 body=30118c6 -->
public async Task<User?> GetByName(string name)
{
var filter = Builders<User>
@@ -152,6 +159,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// <param name="user">The user entity whose fields will be applied to the existing record, identified by <see cref="User.Id"/>.</param>
/// <param name="updatePass">If <c>true</c>, the password field is included in the update; if <c>false</c>, the password is not modified.</param>
/// <returns>The updated <see cref="User"/> retrieved after the update, or <c>null</c> if no matching user was found.</returns>
/// <!-- aidoc:v1 sig=3448f77 body=e54a95d -->
public async Task<User?> UpdateUser(User user, bool updatePass)
{
var filter = Builders<User>
@@ -176,6 +184,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// </summary>
/// <param name="filteredRequest">The pagination filter containing paging details and the optional filter payload (text, user status, and user type) used to build the MongoDB query.</param>
/// <returns>An <see cref="IFindFluent{TDocument, TProjection}"/> of <see cref="User"/> sorted ascending by user name and shaped by the assembled filter definitions.</returns>
/// <!-- aidoc:v1 sig=0f10830 body=0c62e4a -->
public IFindFluent<User, User> GetPaginatedUsers(PaginationFilter filteredRequest)
{
// Crear variable con la clase que construye los filtros que necesitamos
@@ -215,6 +224,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// Retrieves the system user identified by the username "System", creating and inserting a new one with default credentials if no existing user is found.
/// </summary>
/// <returns>The existing system user if found; otherwise, the newly created and inserted system user.</returns>
/// <!-- aidoc:v1 sig=26219ff body=775a713 -->
public async Task<User> GetOrCreateSystemUser()
{
var user = await GetByUserName("System");
@@ -236,6 +246,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// <summary>
/// Inserts the initial load of data by ensuring that the system user exists, creating one if necessary.
/// </summary>
/// <!-- aidoc:v1 sig=ccdefcf body=eb41bb0 -->
public sealed override async Task InsertInitialLoad()
{
await GetOrCreateSystemUser();
@@ -249,6 +260,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// <param name="filters">The list of filter definitions to be combined with logical AND.</param>
/// <param name="sort">The sort definition to apply to the query results.</param>
/// <returns>A fluent find query for the <see cref="User"/> collection with the combined filter and sort applied.</returns>
/// <!-- aidoc:v1 sig=65f1029 body=9a8a34a -->
private IFindFluent<User, User> CreateFindFluent(List<FilterDefinition<User>> filters, SortDefinition<User> sort)
{
var combinedFilter = filters.Any()
@@ -264,6 +276,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// </summary>
/// <param name="type">The user type to filter by. If null or not one of the handled values, no filter is added.</param>
/// <returns>A list of FilterDefinition objects matching the specified user type, or an empty list if no specific type was matched.</returns>
/// <!-- aidoc:v1 sig=ef9cd45 body=04622cf -->
private List<FilterDefinition<User>> GetUserTypeFilter(UserEnum.Type? type)
{
var filters = new List<FilterDefinition<User>>();
@@ -287,6 +300,7 @@ public class UserRepository : MongoRepository<User>, IUserRepository
/// </summary>
/// <param name="status">The user status used to select which filter combination is applied; a <c>null</c> or unhandled value yields an empty filter list.</param>
/// <returns>A list of <see cref="FilterDefinition{TDocument}"/> filters that should be combined to query <see cref="User"/> documents for the specified status.</returns>
/// <!-- aidoc:v1 sig=afc76fe body=92c7666 -->
private List<FilterDefinition<User>> GetUserStatusFilter(StatusEnum.User? status)
{
var filters = new List<FilterDefinition<User>>();