From aedd17ca7f7a8adae3cd06bafa6b84ffab3c5e27 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 29 May 2026 15:56:35 -0400 Subject: [PATCH] feat(configdb): native alarm source repository CRUD + eager-load includes --- .../Repositories/ITemplateEngineRepository.cs | 24 ++++++ .../Repositories/TemplateEngineRepository.cs | 86 +++++++++++++++++++ .../TemplateEngineRepositoryTests.cs | 28 ++++++ 3 files changed, 138 insertions(+) diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Interfaces/Repositories/ITemplateEngineRepository.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Interfaces/Repositories/ITemplateEngineRepository.cs index d565617b..b666318f 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Commons/Interfaces/Repositories/ITemplateEngineRepository.cs +++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Interfaces/Repositories/ITemplateEngineRepository.cs @@ -96,6 +96,18 @@ public interface ITemplateEngineRepository /// Cancellation token. Task DeleteTemplateAlarmAsync(int id, CancellationToken cancellationToken = default); + // TemplateNativeAlarmSource + /// Retrieves a template native alarm source by ID. + Task GetTemplateNativeAlarmSourceByIdAsync(int id, CancellationToken cancellationToken = default); + /// Retrieves native alarm sources for a template. + Task> GetNativeAlarmSourcesByTemplateIdAsync(int templateId, CancellationToken cancellationToken = default); + /// Adds a new template native alarm source. + Task AddTemplateNativeAlarmSourceAsync(TemplateNativeAlarmSource source, CancellationToken cancellationToken = default); + /// Updates an existing template native alarm source. + Task UpdateTemplateNativeAlarmSourceAsync(TemplateNativeAlarmSource source, CancellationToken cancellationToken = default); + /// Deletes a template native alarm source by ID. + Task DeleteTemplateNativeAlarmSourceAsync(int id, CancellationToken cancellationToken = default); + // TemplateScript /// Retrieves a template script by ID. /// The script ID. @@ -214,6 +226,18 @@ public interface ITemplateEngineRepository /// Cancellation token. Task DeleteInstanceAlarmOverrideAsync(int id, CancellationToken cancellationToken = default); + // InstanceNativeAlarmSourceOverride + /// Retrieves native alarm source overrides for an instance. + Task> GetNativeAlarmSourceOverridesByInstanceIdAsync(int instanceId, CancellationToken cancellationToken = default); + /// Retrieves a single native alarm source override by instance + source canonical name. + Task GetNativeAlarmSourceOverrideAsync(int instanceId, string sourceCanonicalName, CancellationToken cancellationToken = default); + /// Adds a new instance native alarm source override. + Task AddInstanceNativeAlarmSourceOverrideAsync(InstanceNativeAlarmSourceOverride ovr, CancellationToken cancellationToken = default); + /// Updates an existing instance native alarm source override. + Task UpdateInstanceNativeAlarmSourceOverrideAsync(InstanceNativeAlarmSourceOverride ovr, CancellationToken cancellationToken = default); + /// Deletes an instance native alarm source override by ID. + Task DeleteInstanceNativeAlarmSourceOverrideAsync(int id, CancellationToken cancellationToken = default); + // InstanceConnectionBinding /// Retrieves connection bindings for an instance. /// The instance ID. diff --git a/src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Repositories/TemplateEngineRepository.cs b/src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Repositories/TemplateEngineRepository.cs index f79cfd81..ac5e8647 100644 --- a/src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Repositories/TemplateEngineRepository.cs +++ b/src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Repositories/TemplateEngineRepository.cs @@ -29,6 +29,7 @@ public class TemplateEngineRepository : ITemplateEngineRepository .Include(t => t.Alarms) .Include(t => t.Scripts) .Include(t => t.Compositions) + .Include(t => t.NativeAlarmSources) .AsSplitQuery() .FirstOrDefaultAsync(t => t.Id == id, cancellationToken); } @@ -59,6 +60,7 @@ public class TemplateEngineRepository : ITemplateEngineRepository .Include(t => t.Alarms) .Include(t => t.Scripts) .Include(t => t.Compositions) + .Include(t => t.NativeAlarmSources) .AsSplitQuery() .ToListAsync(cancellationToken); } @@ -71,6 +73,7 @@ public class TemplateEngineRepository : ITemplateEngineRepository .Include(t => t.Alarms) .Include(t => t.Scripts) .Include(t => t.Compositions) + .Include(t => t.NativeAlarmSources) .AsSplitQuery() .ToListAsync(cancellationToken); } @@ -188,6 +191,45 @@ public class TemplateEngineRepository : ITemplateEngineRepository } } + // TemplateNativeAlarmSource + + /// + public async Task GetTemplateNativeAlarmSourceByIdAsync(int id, CancellationToken cancellationToken = default) + { + return await _context.TemplateNativeAlarmSources.FindAsync(new object[] { id }, cancellationToken); + } + + /// + public async Task> GetNativeAlarmSourcesByTemplateIdAsync(int templateId, CancellationToken cancellationToken = default) + { + return await _context.TemplateNativeAlarmSources + .Where(s => s.TemplateId == templateId) + .ToListAsync(cancellationToken); + } + + /// + public async Task AddTemplateNativeAlarmSourceAsync(TemplateNativeAlarmSource source, CancellationToken cancellationToken = default) + { + await _context.TemplateNativeAlarmSources.AddAsync(source, cancellationToken); + } + + /// + public Task UpdateTemplateNativeAlarmSourceAsync(TemplateNativeAlarmSource source, CancellationToken cancellationToken = default) + { + _context.TemplateNativeAlarmSources.Update(source); + return Task.CompletedTask; + } + + /// + public async Task DeleteTemplateNativeAlarmSourceAsync(int id, CancellationToken cancellationToken = default) + { + var source = await _context.TemplateNativeAlarmSources.FindAsync(new object[] { id }, cancellationToken); + if (source != null) + { + _context.TemplateNativeAlarmSources.Remove(source); + } + } + // TemplateScript /// @@ -275,6 +317,7 @@ public class TemplateEngineRepository : ITemplateEngineRepository .Include(i => i.AttributeOverrides) .Include(i => i.AlarmOverrides) .Include(i => i.ConnectionBindings) + .Include(i => i.NativeAlarmSourceOverrides) .AsSplitQuery() .FirstOrDefaultAsync(i => i.Id == id, cancellationToken); } @@ -286,6 +329,7 @@ public class TemplateEngineRepository : ITemplateEngineRepository .Include(i => i.AttributeOverrides) .Include(i => i.AlarmOverrides) .Include(i => i.ConnectionBindings) + .Include(i => i.NativeAlarmSourceOverrides) .AsSplitQuery() .ToListAsync(cancellationToken); } @@ -306,6 +350,7 @@ public class TemplateEngineRepository : ITemplateEngineRepository .Include(i => i.AttributeOverrides) .Include(i => i.AlarmOverrides) .Include(i => i.ConnectionBindings) + .Include(i => i.NativeAlarmSourceOverrides) .AsSplitQuery() .ToListAsync(cancellationToken); } @@ -317,6 +362,7 @@ public class TemplateEngineRepository : ITemplateEngineRepository .Include(i => i.AttributeOverrides) .Include(i => i.AlarmOverrides) .Include(i => i.ConnectionBindings) + .Include(i => i.NativeAlarmSourceOverrides) .AsSplitQuery() .FirstOrDefaultAsync(i => i.UniqueName == uniqueName, cancellationToken); } @@ -419,6 +465,46 @@ public class TemplateEngineRepository : ITemplateEngineRepository } } + // InstanceNativeAlarmSourceOverride + + /// + public async Task> GetNativeAlarmSourceOverridesByInstanceIdAsync(int instanceId, CancellationToken cancellationToken = default) + { + return await _context.InstanceNativeAlarmSourceOverrides + .Where(o => o.InstanceId == instanceId) + .ToListAsync(cancellationToken); + } + + /// + public async Task GetNativeAlarmSourceOverrideAsync(int instanceId, string sourceCanonicalName, CancellationToken cancellationToken = default) + { + return await _context.InstanceNativeAlarmSourceOverrides + .FirstOrDefaultAsync(o => o.InstanceId == instanceId && o.SourceCanonicalName == sourceCanonicalName, cancellationToken); + } + + /// + public async Task AddInstanceNativeAlarmSourceOverrideAsync(InstanceNativeAlarmSourceOverride ovr, CancellationToken cancellationToken = default) + { + await _context.InstanceNativeAlarmSourceOverrides.AddAsync(ovr, cancellationToken); + } + + /// + public Task UpdateInstanceNativeAlarmSourceOverrideAsync(InstanceNativeAlarmSourceOverride ovr, CancellationToken cancellationToken = default) + { + _context.InstanceNativeAlarmSourceOverrides.Update(ovr); + return Task.CompletedTask; + } + + /// + public async Task DeleteInstanceNativeAlarmSourceOverrideAsync(int id, CancellationToken cancellationToken = default) + { + var ovr = await _context.InstanceNativeAlarmSourceOverrides.FindAsync(new object[] { id }, cancellationToken); + if (ovr != null) + { + _context.InstanceNativeAlarmSourceOverrides.Remove(ovr); + } + } + // InstanceConnectionBinding /// diff --git a/tests/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests/TemplateEngineRepositoryTests.cs b/tests/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests/TemplateEngineRepositoryTests.cs index 7c8b634e..d5dc2112 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests/TemplateEngineRepositoryTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests/TemplateEngineRepositoryTests.cs @@ -147,4 +147,32 @@ public class TemplateEngineRepositoryTests : IDisposable Assert.NotNull(loaded); Assert.Equal(baseTemplate.Id, loaded!.ParentTemplateId); } + + [Fact] + public async Task AddAndGetNativeAlarmSourcesByTemplateId_RoundTrips() + { + var t = new Template("T"); + _context.Templates.Add(t); + await _context.SaveChangesAsync(); + + await _repository.AddTemplateNativeAlarmSourceAsync( + new TemplateNativeAlarmSource("S") { TemplateId = t.Id, ConnectionName = "C", SourceReference = "r" }); + await _context.SaveChangesAsync(); + + var list = await _repository.GetNativeAlarmSourcesByTemplateIdAsync(t.Id); + Assert.Single(list); + Assert.Equal("S", list[0].Name); + } + + [Fact] + public async Task GetTemplateWithChildren_IncludesNativeAlarmSources() + { + var t = new Template("T"); + t.NativeAlarmSources.Add(new TemplateNativeAlarmSource("S") { ConnectionName = "C", SourceReference = "r" }); + _context.Templates.Add(t); + await _context.SaveChangesAsync(); + + var loaded = await _repository.GetTemplateWithChildrenAsync(t.Id); + Assert.Single(loaded!.NativeAlarmSources); + } }