using HrynCo.NotificationService.DAL.Abstract.PushChannels; using HrynCo.NotificationService.DAL.EF.Entities; using Microsoft.EntityFrameworkCore; namespace HrynCo.NotificationService.DAL.EF.Repositories; internal sealed class PushChannelRepository(NotificationDbContext db, TemplateMutationRunner mutations) : IPushChannelRepository { public async Task> GetAllAsync(CancellationToken ct = default) => await ReadModels().OrderBy(c => c.ServiceName).ToListAsync(ct); public Task GetByIdAsync(Guid id, CancellationToken ct = default) => ReadModels().SingleOrDefaultAsync(c => c.Id == id, ct); public Task GetActiveForServiceAsync(Guid serviceId, CancellationToken ct = default) => ReadModels().SingleOrDefaultAsync(c => c.ServiceId == serviceId && c.IsActive, ct); public Task GetCredentialsAsync(Guid id, CancellationToken ct = default) => db.PushChannels.AsNoTracking().Where(c => c.Id == id).Select(c => c.CredentialsJson).SingleOrDefaultAsync(ct); public Task SaveAsync(PushChannel channel, string credentialsJson, bool isNew, CancellationToken ct = default) => mutations.ExecuteAsync(async () => { await ValidateServiceAsync(channel, ct); var entity = await LoadForSaveAsync(channel.Id, isNew, ct); entity.ServiceId = channel.ServiceId; entity.FirebaseProjectId = channel.FirebaseProjectId; entity.CredentialsJson = credentialsJson; entity.IsActive = channel.IsActive; entity.Updated = isNew ? null : DateTimeOffset.UtcNow; channel.Id = entity.Id; }, ct); private async Task ValidateServiceAsync(PushChannel channel, CancellationToken ct) { if (!await db.Services.AnyAsync(s => s.Id == channel.ServiceId, ct)) throw new PushChannelWriteException("Select an existing service.", false); if (await db.PushChannels.AnyAsync(c => c.ServiceId == channel.ServiceId && c.Id != channel.Id, ct)) throw new PushChannelWriteException("This service already has a push channel. Edit that channel instead."); } private async Task LoadForSaveAsync(Guid id, bool isNew, CancellationToken ct) { if (!isNew) return await db.PushChannels.SingleOrDefaultAsync(c => c.Id == id, ct) ?? throw new PushChannelWriteException("The push channel no longer exists. Reload the list."); var entity = new PushChannelEntity { Id = id, FirebaseProjectId = string.Empty, CredentialsJson = "{}", Created = DateTimeOffset.UtcNow }; db.PushChannels.Add(entity); return entity; } private IQueryable ReadModels() => db.PushChannels.AsNoTracking().Select(c => new PushChannel { Id = c.Id, ServiceId = c.ServiceId, ServiceName = c.Service.Name, FirebaseProjectId = c.FirebaseProjectId, IsActive = c.IsActive, Created = c.Created, Updated = c.Updated }); }