using adas_core.Application.Repositories.Interfaces; using adas_core.Domain.Models.AppSettings; using adas_core.Domain.Models.MongoModels; using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; using Serilog; using MongoUtils = adas_core.Infrastructure.Utils.MongoUtils; 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. /// public class NoticeRepository : MongoRepository, INoticeRepository { private readonly ApiSettings _apiSettings; /// /// Initializes a new instance of the NoticeRepository. /// /// API settings containing collection names configuration. /// The MongoDB database instance. /// Thrown when apiSettings is null. public NoticeRepository(IOptions? apiSettings, IMongoDatabase database) : base(database) { if (apiSettings != null) _apiSettings = apiSettings.Value; else throw new ArgumentNullException(nameof(apiSettings)); } /// /// Gets the name of the collection for notices. /// /// The collection name from API settings. public override string GetCollectionName() { return _apiSettings.Notices; } /// /// Inserts a new notice into the database. /// Automatically sets the NoticeDate to UTC current date and time before inserting. /// /// The Notice entity to insert. /// Logs warning and silently fails on insertion error. public override async Task InsertOneAsync(Notice notice) { try { notice.NoticeDate = DateTime.UtcNow; await Collection.InsertOneAsync(notice); } catch (Exception e) { Log.Warning("Exception trying to insert notice: {notice}. Exception {e}", notice, e); } } /// /// Deletes a notice by its ID. /// /// The ObjectId of the notice to delete. /// Throws and re-throws exceptions after logging. public async Task Delete(ObjectId id) { try { var filter = Builders.Filter.Eq(x => x.Id, id); await Collection.DeleteOneAsync(filter, null); } catch (Exception e) { Log.Error("Exception trying to delete notice: {id}. Exception {e}", id, e); throw; } } /// /// Updates an existing notice with new values. /// /// The Notice entity with updated values. /// Throws and re-throws exceptions after logging. public async Task Update(Notice notice) { try { await UpdateOneAsync(notice.Id, notice); } catch (Exception e) { Log.Error("Exception trying to update notice: {notice}. Exception {e}", notice, e); throw; } } /// /// Retrieves all notices from the database. /// /// An enumerable of all Notice entities. /// Logs errors and returns empty list on failure. public async Task> FindAll() { try { var result = await Collection.FindAsync(_ => true); return await result.ToListAsync(); } catch (Exception ex) { Log.Error("Error getting all notices. Exception: {ex}", ex); return []; } } /// /// Retrieves a notice by its ID. /// /// The ObjectId of the notice to retrieve. /// The Notice if found; otherwise, null. /// Logs errors and returns null on failure. public async Task FindById(ObjectId id) { try { var filter = Builders.Filter.Eq(p => p.Id, id); var result = await Collection.FindAsync(filter); return await result.FirstOrDefaultAsync(); } catch (Exception ex) { Log.Error("Error searching notice by id: {id}. Exception: {ex}", id, ex); return null; } } /// /// Retrieves all notices for a specific date. /// /// The date to filter notices by. /// An enumerable of Notice entities matching the date, or null on error. /// Logs errors and returns null on failure. public async Task?> FindByDate(DateTime date) { try { var filter = Builders.Filter.Eq(p => p.NoticeDate, date); var result = await Collection.FindAsync(filter); return result.ToEnumerable(); } catch (Exception ex) { Log.Error("Error searching notice by date: {date}. Exception: {ex}", date, ex); return null; } } /// /// Retrieves all notices of a specific type. /// /// The notice type to filter by. /// An enumerable of Notice entities matching the type, or null on error. /// Logs errors and returns null on failure. public async Task?> FindByType(string type) { try { var filter = Builders.Filter.Eq(p => p.NoticeType, type); var result = await Collection.FindAsync(filter); return result.ToEnumerable(); } catch (Exception ex) { Log.Error("Error searching notice by type: {date}. Exception: {ex}", type, ex); return null; } } /// /// Retrieves all notices associated with a specific display. /// /// The ObjectId of the display to filter by. /// An enumerable of Notice entities for the display, or null on error. /// Logs errors and returns null on failure. public async Task?> FindByDisplayId(ObjectId displayId) { try { var filter = Builders.Filter.Eq(p => p.DisplayId, displayId); var result = await Collection.FindAsync(filter); return result.ToEnumerable(); } catch (Exception ex) { Log.Error("Error searching notices by display id: {id}. Exception: {ex}", displayId, ex); return null; } } /// /// Creates the necessary indexes for the Notice collection. /// Creates compound indexes on (noticeType, noticeDate) and (noticeDate) for improved query performance. /// public override async Task CreateIndexes() { var options = new CreateIndexOptions { Background = true, Unique = false }; var indexes = new List> { new("{ noticeType: 1, noticeDate: -1 }", options), new("{ noticeDate: -1 }", options) }; await MongoUtils.EnsureIndexes(Collection, indexes); } }