5a878b78d4
Add missing <summary>/<param>/<returns>/<typeparam> tags and switch interface implementations to <inheritdoc/> across 106 files; strip project bookkeeping identifiers (Task NN, #05-TNN, PLAN-04, StoreAndForward-0NN) from shipped code comments while preserving the descriptive rationale. Comment-only: zero code-logic lines changed; solution builds 0/0. Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
120 lines
6.1 KiB
C#
120 lines
6.1 KiB
C#
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates;
|
|
using ZB.MOM.WW.ScadaBridge.Transport.Serialization;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.Transport.Import;
|
|
|
|
/// <summary>
|
|
/// The single source of truth for "has this template child changed?": the
|
|
/// field-for-field equality between a persisted template-child entity and its bundle
|
|
/// DTO. Every writable field is compared.
|
|
/// <para>
|
|
/// BOTH the Preview diff (<see cref="ArtifactDiff.CompareTemplate"/>) and the
|
|
/// Overwrite child-sync (<c>BundleImporter.SyncTemplate*Async</c>) MUST route their
|
|
/// change detection through these methods so a Preview can never disagree with what
|
|
/// an Overwrite actually writes. Historically the two drifted — the diff omitted
|
|
/// <c>ElementDataType</c>, <c>ExecutionTimeoutSeconds</c>, the alarm on-trigger
|
|
/// script, and <c>LockedInDerived</c> — reporting <c>Identical</c> for artifacts an
|
|
/// Overwrite would in fact mutate. Adding a writable field to any template-child
|
|
/// entity means adding it here, once.
|
|
/// </para>
|
|
/// </summary>
|
|
internal static class TemplateChildEquality
|
|
{
|
|
/// <summary>
|
|
/// True when the persisted attribute equals its bundle DTO across every writable
|
|
/// field. The single source of truth for "attribute changed"; both ArtifactDiff
|
|
/// and <c>SyncTemplateAttributesAsync</c> call it.
|
|
/// <para>
|
|
/// Callers that normalise the DTO <c>Value</c> before comparing (the importer
|
|
/// normalises List values) pass a DTO whose <c>Value</c> is already normalised.
|
|
/// </para>
|
|
/// </summary>
|
|
/// <param name="e">The persisted template attribute.</param>
|
|
/// <param name="i">The bundle DTO to compare against.</param>
|
|
/// <returns><c>true</c> when every writable field matches.</returns>
|
|
public static bool AttributesEqual(TemplateAttribute e, TemplateAttributeDto i) =>
|
|
e.Value == i.Value
|
|
&& e.DataType == i.DataType
|
|
&& e.ElementDataType == i.ElementDataType
|
|
&& e.IsLocked == i.IsLocked
|
|
&& e.LockedInDerived == i.LockedInDerived
|
|
&& e.Description == i.Description
|
|
&& e.DataSourceReference == i.DataSourceReference;
|
|
|
|
/// <summary>
|
|
/// True when the persisted alarm equals its bundle DTO across every writable
|
|
/// field, including the on-trigger script binding. Bundles reference the
|
|
/// on-trigger script by NAME (ids are environment-specific), so the caller
|
|
/// supplies <paramref name="scriptNameById"/> — a resolver over the alarm's own
|
|
/// template scripts — to map the persisted <c>OnTriggerScriptId</c> FK back to a
|
|
/// name for comparison. The single source of truth for "alarm changed"; both
|
|
/// ArtifactDiff and <c>SyncTemplateAlarmsAsync</c> call it.
|
|
/// </summary>
|
|
/// <param name="e">The persisted template alarm.</param>
|
|
/// <param name="i">The bundle DTO to compare against.</param>
|
|
/// <param name="scriptNameById">Resolver mapping an on-trigger script id to its name.</param>
|
|
/// <returns><c>true</c> when every writable field matches.</returns>
|
|
public static bool AlarmsEqual(TemplateAlarm e, TemplateAlarmDto i, Func<int?, string?> scriptNameById) =>
|
|
e.Description == i.Description
|
|
&& e.PriorityLevel == i.PriorityLevel
|
|
&& e.TriggerType == i.TriggerType
|
|
&& e.TriggerConfiguration == i.TriggerConfiguration
|
|
&& e.IsLocked == i.IsLocked
|
|
&& e.LockedInDerived == i.LockedInDerived
|
|
&& scriptNameById(e.OnTriggerScriptId) == i.OnTriggerScriptName;
|
|
|
|
/// <summary>
|
|
/// True when the persisted script equals its bundle DTO across every writable
|
|
/// field. The single source of truth for "script changed"; both ArtifactDiff
|
|
/// (via <c>DiffScriptChildren</c>) and <c>SyncTemplateScriptsAsync</c> call it.
|
|
/// </summary>
|
|
/// <param name="e">The persisted template script.</param>
|
|
/// <param name="i">The bundle DTO to compare against.</param>
|
|
/// <returns><c>true</c> when every writable field matches.</returns>
|
|
public static bool ScriptsEqual(TemplateScript e, TemplateScriptDto i) =>
|
|
string.Equals(e.Code, i.Code, StringComparison.Ordinal)
|
|
&& e.TriggerType == i.TriggerType
|
|
&& e.TriggerConfiguration == i.TriggerConfiguration
|
|
&& e.ParameterDefinitions == i.ParameterDefinitions
|
|
&& e.ReturnDefinition == i.ReturnDefinition
|
|
&& e.IsLocked == i.IsLocked
|
|
&& e.LockedInDerived == i.LockedInDerived
|
|
&& e.MinTimeBetweenRuns == i.MinTimeBetweenRuns
|
|
&& e.ExecutionTimeoutSeconds == i.ExecutionTimeoutSeconds;
|
|
|
|
/// <summary>
|
|
/// True when the persisted native alarm source equals its bundle DTO across every
|
|
/// writable field. The single source of truth for "native alarm source changed";
|
|
/// both ArtifactDiff and <c>SyncTemplateNativeAlarmSourcesAsync</c> call it.
|
|
/// </summary>
|
|
/// <param name="e">The persisted native alarm source.</param>
|
|
/// <param name="i">The bundle DTO to compare against.</param>
|
|
/// <returns><c>true</c> when every writable field matches.</returns>
|
|
public static bool NativeAlarmSourcesEqual(TemplateNativeAlarmSource e, TemplateNativeAlarmSourceDto i) =>
|
|
e.Description == i.Description
|
|
&& e.ConnectionName == i.ConnectionName
|
|
&& e.SourceReference == i.SourceReference
|
|
&& e.ConditionFilter == i.ConditionFilter
|
|
&& e.IsLocked == i.IsLocked
|
|
&& e.IsInherited == i.IsInherited
|
|
&& e.LockedInDerived == i.LockedInDerived;
|
|
|
|
/// <summary>
|
|
/// Builds a resolver mapping a template script id → its name over the given
|
|
/// scripts, for the alarm on-trigger comparison. Returns null for a null id or an
|
|
/// id absent from the set.
|
|
/// </summary>
|
|
/// <param name="scripts">The template scripts to index by id.</param>
|
|
/// <returns>A resolver mapping a script id to its name, or null when unresolved.</returns>
|
|
public static Func<int?, string?> ScriptNameResolver(IEnumerable<TemplateScript> scripts)
|
|
{
|
|
var byId = new Dictionary<int, string>();
|
|
foreach (var s in scripts)
|
|
{
|
|
byId[s.Id] = s.Name;
|
|
}
|
|
|
|
return id => id is { } sid && byId.TryGetValue(sid, out var name) ? name : null;
|
|
}
|
|
}
|