docs(iec62304): [REL-1.0.2] apply curated XML doc review updates

This commit is contained in:
n8n IEC 62304 Bot
2026-07-02 12:27:30 +02:00
parent 7de114a95a
commit 49def4ee2d
@@ -114,12 +114,10 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Updates an existing master list entity with full replacement. /// Upserts the specified <paramref name="entity"/> in the collection, replacing the document matched by its identifier or inserting it when no match is found. Exceptions are logged and rethrown to the caller.
/// </summary> /// </summary>
/// <param name="entity">The entity with updated values.</param> /// <param name="entity">The entity to persist; its identifier is used as the filter and its state replaces the existing document or creates a new one when absent.</param>
/// <exception cref="Exception">Throws and re-throws exceptions after logging.</exception> /// <!-- aidoc:v1 sig=019b691 body=863650a -->
/// <!-- aidoc-review:v1 severity=medium kind=wrong_summary
/// "Summary states 'Updates an existing' entity, but the ReplaceOptions { IsUpsert = true } means the entity will be inserted if it does not already exist, so the 'existing' qualifier is contradicted by the code's actual behavior." -->
public async Task Update(T entity) public async Task Update(T entity)
{ {
try try
@@ -169,17 +167,11 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Finds a master list entity by its ID with options projection limited to 100 items. /// Asynchronously retrieves an entity of type <typeparamref name="T"/> from the collection using its <see cref="ObjectId"/>, applying a projection that truncates the "options" field to a maximum of 100 elements. Returns <c>null</c> when no document matches the identifier or when an exception is thrown, in which case the exception is logged and swallowed.
/// </summary> /// </summary>
/// <param name="id">The ObjectId of the entity to retrieve.</param> /// <param name="id">The <see cref="ObjectId"/> identifier of the entity to look up.</param>
/// <returns>The MasterList entity if found; otherwise, null.</returns> /// <returns>A <see cref="Task{T}"/> that resolves to the matching entity of type <typeparamref name="T"/>, or <c>null</c> if the entity is not found or an error occurs during retrieval.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception> /// <!-- aidoc:v1 sig=81ac96a body=1519944 -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Method is generic (returns Task<T?>) and works on any entity type T, not specifically a 'master list entity'." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "Documentation says it returns 'The MasterList entity' but the method actually returns Task<T?>, a generic type." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "Documents <exception cref=\"Exception\"> but the catch block swallows all exceptions and never rethrows, so the method never throws." -->
public async Task<T?> FindById(ObjectId id) public async Task<T?> FindById(ObjectId id)
{ {
try try
@@ -203,16 +195,13 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Finds a specific option within a master list by master and option IDs with locale translation. /// Retrieves a single <see cref="OptionList"/> item by its parent master identifier and option identifier, resolving the display name according to the requested <paramref name="locale"/> using the aggregation translation logic embedded in the pipeline.
/// Uses MongoDB aggregation to apply translations and return the translated option.
/// </summary> /// </summary>
/// <param name="masterId">The ObjectId of the master list.</param> /// <param name="masterId">The <see cref="MongoDB.Bson.ObjectId"/> of the master document whose embedded options collection will be searched.</param>
/// <param name="optionId">The ObjectId of the option to retrieve.</param> /// <param name="optionId">The <see cref="MongoDB.Bson.ObjectId"/> of the specific <see cref="OptionList"/> to retrieve from the unwound options array.</param>
/// <param name="locale">The locale for translation.</param> /// <param name="locale">The <see cref="LocaleEnum"/> used to select the localized name; when equal to <see cref="LocaleEnum.Default"/> or matching the document's default locale, the base name is returned, otherwise the matching <c>localeItems</c> entry is used with a fallback to the base name.</param>
/// <returns>The OptionList with translated fields if found; otherwise, null.</returns> /// <returns>A <see cref="Task"/> that yields the matching <see cref="OptionList"/> deserialized from the aggregation result, or <c>null</c> if no document is found or the operation fails.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception> /// <!-- aidoc:v1 sig=fdb2628 body=0e4983e -->
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions internally (try/catch) and never throws; documenting <exception cref=\"Exception\"> is misleading. Callers will not receive any exception to handle." -->
public async Task<OptionList?> FindOptionItemById(ObjectId masterId, ObjectId optionId, LocaleEnum locale) public async Task<OptionList?> FindOptionItemById(ObjectId masterId, ObjectId optionId, LocaleEnum locale)
{ {
try try
@@ -352,14 +341,12 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Finds a specific option within a master list by master and option IDs without locale translation. /// Asynchronously retrieves the <see cref="OptionList"/> option that matches the supplied <paramref name="masterId"/> and <paramref name="optionId"/> from the parent document's options array, returning the first match or <see langword="null"/> when no option is found or when an error is logged.
/// </summary> /// </summary>
/// <param name="masterId">The ObjectId of the master list.</param> /// <param name="masterId">The identifier of the master document that owns the options array.</param>
/// <param name="optionId">The ObjectId of the option to retrieve.</param> /// <param name="optionId">The identifier of the specific option to locate within that array.</param>
/// <returns>The OptionList if found; otherwise, null.</returns> /// <returns>A <see cref="Task{T}"/> that yields the matching <see cref="OptionList"/>, or <see langword="null"/> if the lookup yields no result or the operation fails.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception> /// <!-- aidoc:v1 sig=ccc34cb body=71837cc -->
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method contains a catch-all for Exception and never lets it propagate to callers, so documenting <exception cref=\"Exception\"> is misleading; the tag should be removed since no exception escapes this method." -->
public async Task<OptionList?> FindOptionItemById(ObjectId masterId, ObjectId optionId) public async Task<OptionList?> FindOptionItemById(ObjectId masterId, ObjectId optionId)
{ {
try try
@@ -385,17 +372,12 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Finds a master list entity by its ID with optional locale translation for options. /// Retrieves an entity by its <see cref="ObjectId"/>, applying locale-aware name resolution to the nested options. When <paramref name="locale"/> is <see cref="LocaleEnum.Default"/> or matches the document's default locale, the original option name is used; otherwise the translated name is looked up in <c>localeItems</c> with a fallback to the original name. Returns <c>null</c> when the entity is not found or an error occurs.
/// Uses MongoDB aggregation to unwind options and apply translations.
/// </summary> /// </summary>
/// <param name="id">The ObjectId of the entity to retrieve.</param> /// <param name="id">The <see cref="ObjectId"/> of the document to retrieve.</param>
/// <param name="locale">Optional locale for translated option names.</param> /// <param name="locale">The optional <see cref="LocaleEnum"/> used to resolve translated option names. When <c>null</c> or <see cref="LocaleEnum.Default"/>, the default locale is applied.</param>
/// <returns>The MasterList entity with translated options if found; otherwise, null.</returns> /// <returns>A <see cref="Task{T}"/> containing the localized entity, or <c>null</c> when the entity cannot be found or the aggregation fails.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception> /// <!-- aidoc:v1 sig=cb4a658 body=f2e88d8 -->
/// <!-- aidoc-review:v1 severity=high kind=extra_exception
/// "The <exception cref=\"Exception\"> tag is misleading: the catch block handles all exceptions internally and the method returns null, so no Exception is ever thrown to callers. Listing Exception implies callers must handle it, which they cannot." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "Documentation says 'The MasterList entity' but the method signature is generic Task<T?>, so the returned type is T, not necessarily a MasterList." -->
public async Task<T?> FindById(ObjectId id, LocaleEnum? locale) public async Task<T?> FindById(ObjectId id, LocaleEnum? locale)
{ {
try try
@@ -573,17 +555,13 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Finds a master list entity by its name. /// Asynchronously finds the first entity matching the specified <paramref name="name"/> in the underlying collection,
/// applying a projection that limits the <c>options</c> array to 100 elements. Returns null when no matching document is found,
/// and logs the error and returns null if the lookup throws an exception.
/// </summary> /// </summary>
/// <param name="name">The name of the master list to retrieve.</param> /// <param name="name">The value compared against the entity's <c>Name</c> field to locate the document.</param>
/// <returns>The MasterList entity if found; otherwise, null.</returns> /// <returns>A task that yields the first matching entity of type T, or null if no match is found or the operation fails.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception> /// <!-- aidoc:v1 sig=80a1541 body=8b5b558 -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
/// "The <exception> tag documents Exception being thrown, but the method catches all exceptions internally and returns null instead of letting any exception propagate to the caller." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "The summary specifies a 'master list entity', but the method is generic (T) and could operate on any type with a Name property; the documentation should not assume a specific type." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "The <returns> tag describes a MasterList entity, but the method returns Task<T?> where T is a generic type parameter, not necessarily MasterList." -->
public async Task<T?> FindByName(string name) public async Task<T?> FindByName(string name)
{ {
try try
@@ -619,14 +597,12 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Retrieves paginated master lists with optional text filtering. /// Builds a query for the master list of <typeparamref name="T"/> documents, sorted ascending by the name field.
/// When <paramref name="filter"/> carries non-empty search text, a case-insensitive regex match is applied to the Name property; otherwise the query is returned without additional filtering.
/// </summary> /// </summary>
/// <param name="filter">The pagination and filtering parameters.</param> /// <param name="filter">The <see cref="PaginationFilter"/> providing pagination settings and the optional search text.</param>
/// <returns>A fluent queryable for MasterList results.</returns> /// <returns>An <see cref="IFindFluent{T,T}"/> representing the prepared query, ready for further pagination and execution.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary /// <!-- aidoc:v1 sig=bbb39c7 body=f42ebaa -->
/// "Summary claims the method 'retrieves paginated master lists', but the code only builds filters/sort and returns an IFindFluent without any pagination logic (no Skip/Limit)." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "Returns tag specifies 'MasterList results', but the method is generic and returns IFindFluent<T, T>, not specifically MasterList." -->
public IFindFluent<T, T> GetPaginatedMasterList(PaginationFilter filter) public IFindFluent<T, T> GetPaginatedMasterList(PaginationFilter filter)
{ {
var filterBuilder = Builders<T>.Filter; var filterBuilder = Builders<T>.Filter;
@@ -649,13 +625,12 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Retrieves paginated options within a master list with optional text filtering. /// Retrieves the options belonging to the master list identified by <paramref name="listId"/>, optionally applying a case-insensitive text filter on the option name, description, or type. Returns an empty list when the master list cannot be found.
/// </summary> /// </summary>
/// <param name="filter">The pagination and filtering parameters.</param> /// <param name="filter">A <see cref="PaginationFilter"/> whose <c>FilteredRequest.Text</c> is used to match option fields when provided.</param>
/// <param name="listId">The ObjectId of the master list.</param> /// <param name="listId">The identifier of the master <see cref="OptionList"/> whose options are returned.</param>
/// <returns>A list of filtered OptionList items.</returns> /// <returns>A task that yields a <see cref="List{OptionList}"/> of options matching the filter, or an empty list if the master list does not exist.</returns>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary /// <!-- aidoc:v1 sig=2ac8d75 body=b25fb18 -->
/// "Summary and method name claim 'paginated' results, but the code applies only text filtering with no skip/take/page logic — the PaginationFilter's pagination fields are unused." -->
public async Task<List<OptionList>> GetPaginatedOptions(PaginationFilter filter, ObjectId listId) public async Task<List<OptionList>> GetPaginatedOptions(PaginationFilter filter, ObjectId listId)
{ {
//TODO: LOCALE //TODO: LOCALE
@@ -675,14 +650,14 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Adds a new option to a master list. /// Adds a new <see cref="OptionList"/> entry to the master list identified by <paramref name="id"/>, rejecting duplicates that match the search criteria in <paramref name="opt"/>.
/// When <see cref="FilterOptionListElement.IsFromAdmPanel"/> is set, the provided locale items are reused; otherwise new locale entries are derived from the current default locale (falling back to <see cref="LocaleEnum.Es"/>) through <c>GetNewItemLocale</c>.
/// Returns <see langword="null"/> when the option already exists, the update modifies no documents, or an exception is caught and logged.
/// </summary> /// </summary>
/// <param name="id">The ObjectId of the master list.</param> /// <param name="id">The identifier of the master list to which the option will be appended.</param>
/// <param name="opt">The option element to add.</param> /// <param name="opt">The option payload, including name, type, visual properties, and locale items used to seed translations.</param>
/// <returns>The newly created OptionList if successful; otherwise, null if duplicate exists.</returns> /// <returns>The persisted <see cref="OptionList"/> on success; otherwise, <see langword="null"/> if a duplicate is found, no document is modified, or an error occurs.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception> /// <!-- aidoc:v1 sig=1602f0d body=e7fd138 -->
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions internally and returns null; it never throws an Exception to the caller, so documenting <exception cref=\"Exception\"> is misleading." -->
public async Task<OptionList?> AddOptionToMasterList(ObjectId id, FilterOptionListElement opt) public async Task<OptionList?> AddOptionToMasterList(ObjectId id, FilterOptionListElement opt)
{ {
var exist = await GetMasterListByIdAndSearchOptions(id, opt); var exist = await GetMasterListByIdAndSearchOptions(id, opt);
@@ -722,16 +697,11 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Retrieves all master list entities. /// Asynchronously retrieves all entities from the underlying collection by matching every document.
/// If the retrieval fails, the exception is logged and an empty collection is returned as a fallback.
/// </summary> /// </summary>
/// <returns>An enumerable of all MasterList entities.</returns> /// <returns>A task that yields an <see cref="System.Collections.Generic.IEnumerable{T}"/> of all entities, or an empty collection when an error occurs.</returns>
/// <exception cref="Exception">Logs errors and returns empty list on failure.</exception> /// <!-- aidoc:v1 sig=3a61c61 body=40d7129 -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
/// "Summary says 'Retrieves all master list entities' but the method is generic over T and operates on the configured Collection, not specifically MasterList entities." -->
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
/// "Returns tag says 'An enumerable of all MasterList entities' but the method returns Task<IEnumerable<T>>, where T is a generic type parameter." -->
/// <!-- aidoc-review:v1 severity=high kind=extra_exception
/// "<exception cref=\"Exception\"> implies the method may throw Exception, but the catch block swallows all exceptions and returns an empty list; the method does not throw Exception." -->
public async Task<IEnumerable<T>> GetAll() public async Task<IEnumerable<T>> GetAll()
{ {
try try
@@ -747,12 +717,11 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Retrieves all master list entities without options, returning only metadata. /// Asynchronously retrieves all <see cref="MasterListDto"/> entries from the collection, mapping each result to include its identifier, name, description, list type, and the count of associated options.
/// If an error occurs while accessing the underlying store, the exception is logged and an empty collection is returned.
/// </summary> /// </summary>
/// <returns>An enumerable of MasterListDto containing id, name, description, listType, and options count.</returns> /// <returns>A <see cref="Task{TResult}"/> that yields an <see cref="IEnumerable{MasterListDto}"/> containing the projected master list entries, or an empty collection when the operation fails.</returns>
/// <exception cref="Exception">Logs errors and returns empty list on failure.</exception> /// <!-- aidoc:v1 sig=e493435 body=1c299ba -->
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions internally (try/catch around the entire body) and returns an empty list; it never throws Exception to the caller, so the <exception cref=\"Exception\"> tag is misleading." -->
public async Task<IEnumerable<MasterListDto>> GetAllWithoutOptions() public async Task<IEnumerable<MasterListDto>> GetAllWithoutOptions()
{ {
try try
@@ -777,12 +746,10 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Counts the total number of master list entities in the collection. /// Asynchronously counts all entities in the underlying collection by invoking CountDocumentsAsync with a filter that matches every document. If an exception occurs during the count operation, the error is logged and the method returns <c>0</c> as a safe fallback.
/// </summary> /// </summary>
/// <returns>The total count of entities.</returns> /// <returns>A <see cref="Task{Int32}"/> that resolves to the total number of entities in the collection, or <c>0</c> if the operation fails.</returns>
/// <exception cref="Exception">Logs errors and returns 0 on failure.</exception> /// <!-- aidoc:v1 sig=f1f0a98 body=01cd3d1 -->
/// <!-- aidoc-review:v1 severity=medium kind=wrong_exception
/// "The method catches all Exception internally and returns 0, so it never throws Exception to callers. The <exception cref=\"Exception\"> tag misleads readers into expecting exceptions to propagate." -->
public async Task<int> Count() public async Task<int> Count()
{ {
try try
@@ -798,15 +765,14 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Searches for options within a master list using multiple filter criteria. /// Retrieves the master list of <see cref="OptionList"/> entries associated with the supplied <paramref name="id"/>, applying the optional search and locale filters.
/// Uses MongoDB aggregation pipeline to apply filters and locale translations. /// When <paramref name="filters"/> is <c>null</c> the method short-circuits and returns an empty list; if the <see cref="FilterOptionListElement.Text"/> is provided it takes precedence over <see cref="FilterOptionListElement.Name"/> and <see cref="FilterOptionListElement.Description"/> and is matched as a case-insensitive regex across name and description.
/// The pipeline resolves per-option translations for the requested locale, falling back to the original values when no translation exists, then filters, sorts by name, and returns the result — or an empty list if an exception is encountered.
/// </summary> /// </summary>
/// <param name="id">The ObjectId of the master list.</param> /// <param name="id">The <see cref="ObjectId"/> of the master list document to match in the aggregation pipeline.</param>
/// <param name="filters">The filter criteria including text, name, description, and optionType.</param> /// <param name="filters">The optional <see cref="FilterOptionListElement"/> carrying the search criteria and locale to apply; when <c>null</c> no lookup is performed.</param>
/// <returns>A list of matching OptionList items ordered by name.</returns> /// <returns>A <see cref="Task{List{OptionList}}"/> containing the filtered and locale-resolved options ordered by name, or an empty list when <paramref name="filters"/> is <c>null</c> or the aggregation fails.</returns>
/// <exception cref="Exception">Logs errors and returns empty list on failure.</exception> /// <!-- aidoc:v1 sig=f6ee5be body=17d6a96 -->
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all Exception instances and logs them without rethrowing, so no Exception is propagated to the caller; documenting <exception cref=\"Exception\"> is misleading." -->
public async Task<List<OptionList>> GetMasterListByIdAndSearchOptions(ObjectId id, FilterOptionListElement? filters) public async Task<List<OptionList>> GetMasterListByIdAndSearchOptions(ObjectId id, FilterOptionListElement? filters)
{ {
try try
@@ -1015,15 +981,13 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Updates a specific option within a master list with locale-aware field updates. /// Updates an existing option within a master list identified by <paramref name="id"/>, applying the changes from <paramref name="newOpt"/> in the specified <paramref name="locale"/>. Prevents duplicates by short-circuiting when an option with the same name already exists, routes name changes to either the main field or the locale-specific translation entry depending on whether the supplied locale matches the master's default locale, and respects the per-field required flags defined on the master.
/// </summary> /// </summary>
/// <param name="id">The ObjectId of the master list.</param> /// <param name="id">The <see cref="ObjectId"/> of the master list that contains the option to update.</param>
/// <param name="newOpt">The OptionList with updated values.</param> /// <param name="newOpt">The <see cref="OptionList"/> carrying the new values to be applied to the matching option.</param>
/// <param name="locale">The locale for translation updates.</param> /// <param name="locale">The <see cref="LocaleEnum"/> that determines whether the name is written to the main field or stored as a translation under <c>localeItems</c>.</param>
/// <returns>The updated OptionList if successful; otherwise, null.</returns> /// <returns>A <see cref="Task{T}"/> that yields the updated <see cref="OptionList"/> when the operation succeeds, an existing duplicate when one is detected, or <see langword="null"/> when there is nothing to update, no document was modified, or an error is logged and swallowed.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception> /// <!-- aidoc:v1 sig=e771f23 body=5520a4a -->
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions internally and returns null; it does not propagate any exception to callers, so the <exception cref=\"Exception\"/> tag is misleading." -->
public async Task<OptionList?> UpdateMasterListOption(ObjectId id, OptionList newOpt, LocaleEnum locale) public async Task<OptionList?> UpdateMasterListOption(ObjectId id, OptionList newOpt, LocaleEnum locale)
{ {
// 1. Evitar duplicados // 1. Evitar duplicados
@@ -1118,14 +1082,13 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Updates a specific option within a master list with full replacement. /// Updates an existing option within the master list identified by <paramref name="id"/> with the values supplied in <paramref name="newOpt"/>.
/// Returns <see langword="null"/> when the master list cannot be found, when no document is modified, or when the operation fails.
/// </summary> /// </summary>
/// <param name="id">The ObjectId of the master list.</param> /// <param name="id">The identifier of the master list that contains the option to update.</param>
/// <param name="newOpt">The OptionList with updated values.</param> /// <param name="newOpt">The new option values to persist; its <see cref="OptionList.Id"/> is used to match the existing element.</param>
/// <returns>The updated OptionList if successful; otherwise, null.</returns> /// <returns>The updated <see cref="OptionList"/> item, or <see langword="null"/> if the master list is not found, the option was not updated, or an error occurred.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception> /// <!-- aidoc:v1 sig=6def54c body=9554543 -->
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The <exception cref=\"Exception\"> tag is misleading because the method catches Exception rather than throwing it. The described behavior (log and return null) matches the catch block, but this is not an exception thrown by the method." -->
public async Task<OptionList?> UpdateMasterListOption(ObjectId id, OptionList newOpt) public async Task<OptionList?> UpdateMasterListOption(ObjectId id, OptionList newOpt)
{ {
var master = await FindById(id); var master = await FindById(id);
@@ -1180,16 +1143,14 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Updates the metadata details for a master list. /// Asynchronously updates the option details of a master list document identified by <paramref name="id"/>,
/// applying only the non-null fields supplied in <paramref name="opt"/> (such as <see cref="UpdateMasterListDetailsDto.CanAddElement"/> and <see cref="UpdateMasterListDetailsDto.OptionListDetails"/>).
/// Returns the updated <see cref="UpdateMasterListDetailsDto"/> when the document is modified, or <see langword="null"/> when no document matches the identifier, no fields were changed, or an error occurs while updating.
/// </summary> /// </summary>
/// <param name="id">The ObjectId of the master list.</param> /// <param name="id">The <see cref="ObjectId"/> identifying the master list document to update.</param>
/// <param name="opt">The UpdateMasterListDetailsDto with updated values.</param> /// <param name="opt">The <see cref="UpdateMasterListDetailsDto"/> containing the new values to apply; only non-null properties are included in the update.</param>
/// <returns>The updated UpdateMasterListDetailsDto if successful; otherwise, null.</returns> /// <returns>A <see cref="Task{T}"/> that resolves to the updated <see cref="UpdateMasterListDetailsDto"/> on success, or <see langword="null"/> when the document is not found, not modified, or the operation fails.</returns>
/// <exception cref="Exception">Logs errors and returns null on failure.</exception> /// <!-- aidoc:v1 sig=53d4179 body=49f50ca -->
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions internally and never throws them, so documenting <exception cref=\"Exception\"> is misleading" -->
/// <!-- aidoc-review:v1 severity=medium kind=wrong_summary
/// "Summary says 'metadata details' but the method updates option details (CanAddElement, OptionListDetails)" -->
public async Task<UpdateMasterListDetailsDto?> UpdateOptionDetailsToMasterList(ObjectId id, public async Task<UpdateMasterListDetailsDto?> UpdateOptionDetailsToMasterList(ObjectId id,
UpdateMasterListDetailsDto opt) UpdateMasterListDetailsDto opt)
{ {
@@ -1219,14 +1180,13 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Updates the name of a master list. /// Updates the name of a master list entry identified by <paramref name="id"/>.
/// Returns <c>true</c> when a document was modified, or <c>false</c> when no document matched the filter or an exception is caught and logged.
/// </summary> /// </summary>
/// <param name="id">The ObjectId of the master list.</param> /// <param name="id">The <see cref="ObjectId"/> of the document to update.</param>
/// <param name="name">The new name.</param> /// <param name="name">The new name to assign to the document.</param>
/// <returns>True if the update was successful; otherwise, false.</returns> /// <returns><c>true</c> if the update modified a document; otherwise, <c>false</c>.</returns>
/// <exception cref="Exception">Logs errors and returns false on failure.</exception> /// <!-- aidoc:v1 sig=5b79a51 body=36dfe99 -->
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions internally and never rethrows them, so <exception cref=\"Exception\"> is misleading; callers cannot actually receive an exception from this method." -->
public async Task<bool> UpdateMasterListName(ObjectId id, string name) public async Task<bool> UpdateMasterListName(ObjectId id, string name)
{ {
var filter = Builders<T>.Filter.And( var filter = Builders<T>.Filter.And(
@@ -1247,14 +1207,12 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Updates the description of a master list. /// Updates the description of the master list entry identified by <paramref name="id"/>.
/// </summary> /// </summary>
/// <param name="id">The ObjectId of the master list.</param> /// <param name="id">The <see cref="ObjectId"/> of the master list entry to update.</param>
/// <param name="description">The new description.</param> /// <param name="description">The new description to apply to the entry.</param>
/// <returns>True if the update was successful; otherwise, false.</returns> /// <returns><see langword="true"/> when the document was modified; <see langword="false"/> when no document matched the filter or the update operation failed.</returns>
/// <exception cref="Exception">Logs errors and returns false on failure.</exception> /// <!-- aidoc:v1 sig=5a27a55 body=3552f46 -->
/// <!-- aidoc-review:v1 severity=high kind=extra_exception
/// "The method catches all exceptions internally and returns false; it never throws an Exception, so the <exception cref=\"Exception\"> tag is incorrect." -->
public async Task<bool> UpdateMasterListDescription(ObjectId id, string description) public async Task<bool> UpdateMasterListDescription(ObjectId id, string description)
{ {
var filter = Builders<T>.Filter.And( var filter = Builders<T>.Filter.And(
@@ -1275,14 +1233,12 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Removes an option from a master list by matching all its properties. /// Removes the specified <paramref name="oldOpt"/> entry from the <c>options</c> array of a master list document identified by <paramref name="id"/>. The option is matched by all of its defining properties (name, optionType, iconDefault, iconCategory, iconColor, color, bgColor, isDefault, and description) using a pull filter, and the method returns <see langword="true"/> only when at least one document was modified; if no matching document is found, or if an exception is caught, it is logged and the method returns <see langword="false"/>.
/// </summary> /// </summary>
/// <param name="id">The ObjectId of the master list.</param> /// <param name="id">The <see cref="MongoDB.Bson.ObjectId"/> of the master list document to update.</param>
/// <param name="oldOpt">The OptionList to remove.</param> /// <param name="oldOpt">The <see cref="OptionList"/> whose properties are used to identify which element to pull from the <c>options</c> array.</param>
/// <returns>True if the option was removed; otherwise, false.</returns> /// <returns>A <see cref="Task{Boolean}"/> that resolves to <see langword="true"/> if the document was modified (i.e., the option was removed), or <see langword="false"/> if no document was updated or an error occurred.</returns>
/// <exception cref="Exception">Logs errors and returns false on failure.</exception> /// <!-- aidoc:v1 sig=8de50cd body=d974b9b -->
/// <!-- aidoc-review:v1 severity=high kind=extra_exception
/// "The method catches all exceptions in a try/catch and returns false; it does not throw Exception, so the <exception> tag is misleading." -->
public async Task<bool> RemoveMasterListOption(ObjectId id, OptionList oldOpt) public async Task<bool> RemoveMasterListOption(ObjectId id, OptionList oldOpt)
{ {
var filter = Builders<T>.Filter.Eq("_id", id); var filter = Builders<T>.Filter.Eq("_id", id);
@@ -1311,11 +1267,9 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Creates necessary indexes for the MasterList collection. /// Creates MongoDB indexes for the <see cref="DiagnosisList"/> entity type, adding non-unique background indexes on the <c>options.name</c>, <c>options.description</c>, and <c>options._id</c> fields with Spanish configured as both the default and override language. If the generic type is not <see cref="DiagnosisList"/>, no indexes are created.
/// Currently creates text indexes for DiagnosisList on options.name, options.description, and options._id.
/// </summary> /// </summary>
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary /// <!-- aidoc:v1 sig=4955da2 body=2c8d1f7 -->
/// "Documentation claims 'text indexes' are created, but the code uses Builders<T>.IndexKeys.Ascending(), which creates ascending (non-text) indexes." -->
public override async Task CreateIndexes() public override async Task CreateIndexes()
{ {
if (typeof(T) == typeof(DiagnosisList)) if (typeof(T) == typeof(DiagnosisList))
@@ -1348,14 +1302,12 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Searches for options within a master list using text search with accent-aware regex. /// Retrieves the options of a referenced entity whose <c>name</c> or <c>description</c> match the supplied <paramref name="textSearch"/>, building a case-insensitive regex pattern (via <c>BuildRegexPattern</c>) and filtering through a MongoDB aggregation pipeline against <see cref="Collection"/>. Returns an empty list when <paramref name="textSearch"/> is null, empty, or whitespace, when the entity identified by <paramref name="id"/> cannot be found, or when no options match; any error is logged and an empty list is returned.
/// </summary> /// </summary>
/// <param name="textSearch">Optional text to search within options.</param> /// <param name="textSearch">The free-text query used to match option names and descriptions. A null, empty, or whitespace value short-circuits the search and yields no results.</param>
/// <param name="id">Optional master list ObjectId to filter results.</param> /// <param name="id">The <see cref="ObjectId"/> of the parent entity whose options will be searched. When <c>null</c>, the aggregation matches a literal <c>null</c> identifier.</param>
/// <returns>A list of matching OptionList items ordered by name.</returns> /// <returns>A <see cref="Task{List}"/> containing the matching <see cref="OptionList"/> entries ordered by name, or an empty list when nothing matches or the operation fails.</returns>
/// <exception cref="Exception">Logs errors and returns empty list on failure.</exception> /// <!-- aidoc:v1 sig=6ebeac8 body=1d7bbb7 -->
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The method catches all exceptions internally (catch (Exception ex)) and never throws to the caller; the <exception cref=\"Exception\"> tag is misleading and should be removed. The catch-block description belongs in the summary or remarks instead." -->
private async Task<List<OptionList>> GetOptionsByTextSearch(string? textSearch, ObjectId? id = null) private async Task<List<OptionList>> GetOptionsByTextSearch(string? textSearch, ObjectId? id = null)
{ {
try try
@@ -1428,14 +1380,12 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Creates a fluent query for paginated results with combined filters. /// Creates an <see cref="IFindFluent{T,T}"/> query by combining the provided <paramref name="filters"/> with a logical AND and applying the given <paramref name="sort"/>. When <paramref name="filters"/> is empty, <see cref="MongoDB.Driver.Builders{TDocument}.Filter.Empty"/> is used so that all documents are matched.
/// </summary> /// </summary>
/// <param name="filters">List of filter definitions to apply.</param> /// <param name="filters">The list of <see cref="FilterDefinition{T}"/> instances to combine. When the list is empty, no filtering is applied.</param>
/// <param name="sort">Sort definition for the query results.</param> /// <param name="sort">The <see cref="SortDefinition{T}"/> to apply to the resulting query.</param>
/// <returns>A fluent queryable for T results.</returns> /// <returns>An <see cref="IFindFluent{T,T}"/> configured with the combined filter and sort.</returns>
/// <!-- aidoc:v1 sig=704d715 body=2a35652 --> /// <!-- aidoc:v1 sig=704d715 body=2a35652 -->
/// <!-- aidoc-review:v1 severity=low kind=wrong_summary
/// "Summary states the method creates a fluent query 'for paginated results', but the method body only applies combined filters and sort and performs no pagination (no Skip/Limit). The returned IFindFluent merely supports pagination by the caller." -->
private IFindFluent<T, T> CreateFindFluent(List<FilterDefinition<T>> filters, SortDefinition<T> sort) private IFindFluent<T, T> CreateFindFluent(List<FilterDefinition<T>> filters, SortDefinition<T> sort)
{ {
var combinedFilter = filters.Any() var combinedFilter = filters.Any()
@@ -1445,14 +1395,12 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Generates new locale items for a master list option based on a default locale. /// Builds a new <see cref="Locale"/> by assigning a fresh <see cref="LocaleItem"/> (with <see cref="LocaleItem.Name"/> set to <paramref name="opt"/>) to every property of <see cref="Locale"/> whose name matches a <see cref="LocaleEnum"/> value, skipping <see cref="LocaleEnum.Default"/> and the value supplied through <paramref name="localeList"/>.
/// Creates LocaleItem entries for all locales except the specified default.
/// </summary> /// </summary>
/// <param name="localeList">The default locale to exclude from translations.</param> /// <param name="localeList">The <see cref="LocaleEnum"/> value identifying the locale to omit when populating the resulting <see cref="Locale"/>.</param>
/// <param name="opt">The option name to use as default translation.</param> /// <param name="opt">The name assigned to each created <see cref="LocaleItem"/>.</param>
/// <returns>A Locale object with translations for all other locales.</returns> /// <returns>A <see cref="Locale"/> with a new <see cref="LocaleItem"/> for every locale other than <see cref="LocaleEnum.Default"/> and <paramref name="localeList"/>; properties without a matching enum name are left unset.</returns>
/// <!-- aidoc-review:v1 severity=medium kind=stale_summary /// <!-- aidoc:v1 sig=147db59 body=9b63847 -->
/// "Summary says items are created for all locales except 'the specified default', but the code also always skips LocaleEnum.Default in addition to the localeList parameter; only one exclusion is documented when two occur." -->
private Locale GetNewItemLocale(LocaleEnum localeList, string opt) private Locale GetNewItemLocale(LocaleEnum localeList, string opt)
{ {
var newLocale = new Locale(); var newLocale = new Locale();
@@ -1487,14 +1435,12 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
// Método auxiliar para construir patrones regex con soporte de acentos // Método auxiliar para construir patrones regex con soporte de acentos
/// Builds a regex pattern that matches accented and non-accented versions of vowels. /// <summary>
/// Supports Spanish accent handling (á, é, í, ó, ú) and digits. /// Builds a case-insensitive regex pattern from <paramref name="input"/>, expanding each vowel into a character class that includes its common accented variants (e.g. <c>a</c> → <c>[aáàäâ]</c>). Digits are wrapped in a character class as literal matches, and any other character is appended as-is to be treated literally by the regex engine.
/// </summary> /// </summary>
/// <param name="input">The input string to build the pattern from.</param> /// <param name="input">The source text whose characters are translated into the resulting regex pattern.</param>
/// <returns>A regex-compatible pattern string.</returns> /// <returns>A <see cref="System.String"/> containing the constructed regular expression pattern.</returns>
/// <!-- aidoc:v1 sig=2992c00 body=ae88daf --> /// <!-- aidoc:v1 sig=2992c00 body=ae88daf -->
/// <!-- aidoc-review:v1 severity=low kind=stale_summary
/// "Documentation lists only á, é, í, ó, ú as supported Spanish accents, but the code also handles à, ä, â, è, ë, ê, ì, ï, î, ò, ö, ô, ù, ü, û for each vowel." -->
private static string BuildRegexPattern(string input) private static string BuildRegexPattern(string input)
{ {
var regexPattern = new StringBuilder(); var regexPattern = new StringBuilder();
@@ -1528,16 +1474,17 @@ public class MasterListRepository<T> : MongoRepository<T>, IMasterListRepository
} }
/// <summary> /// <summary>
/// Searches for options within a master list by name with locale translation. /// Retrieves the options of a master list document identified by <paramref name="id"/>, rebuilding each option's
/// Uses MongoDB aggregation pipeline to apply locale-aware filtering. /// <c>Name</c> by selecting the translation matching <paramref name="locale"/> (or falling back to the original name
/// when the locale is the default or no translation exists), and filters the resulting options by exact match against
/// <paramref name="newOptName"/>. Returns the matched options ordered by name, or an empty list if no document is
/// found, no option matches, or an error occurs.
/// </summary> /// </summary>
/// <param name="id">The ObjectId of the master list.</param> /// <param name="id">MongoDB <see cref="ObjectId"/> of the master list document to search.</param>
/// <param name="newOptName">The option name to search for.</param> /// <param name="newOptName">Option name (already resolved against the requested locale) used to filter the options.</param>
/// <param name="locale">The locale for translation.</param> /// <param name="locale">Target <see cref="LocaleEnum"/> used to pick the translated name; the lowercased enum value is matched against the stored locale code.</param>
/// <returns>A list of matching OptionList items ordered by name.</returns> /// <returns>A <see cref="Task{T}"/> of <see cref="List{T}"/> of <see cref="OptionList"/> containing the matching options sorted by name, or an empty list when there is no match or an error is logged.</returns>
/// <exception cref="Exception">Logs errors and returns empty list on failure.</exception> /// <!-- aidoc:v1 sig=342dc63 body=21f31fc -->
/// <!-- aidoc-review:v1 severity=medium kind=extra_exception
/// "The <exception cref=\"Exception\"> tag documents an exception that is never thrown to the caller: the method catches all exceptions internally, logs them, and returns an empty list. The descriptive text 'Logs errors and returns empty list on failure' is accurate but should not be tagged as an exception." -->
private async Task<List<OptionList>> GetMasterListByIdAndTextSearch( private async Task<List<OptionList>> GetMasterListByIdAndTextSearch(
ObjectId id, string newOptName, LocaleEnum locale) ObjectId id, string newOptName, LocaleEnum locale)
{ {