feat(commons): carry DataSourceReferenceOverride on ConnectionBinding (additive)
This commit is contained in:
@@ -12,8 +12,17 @@ public record MgmtDeleteInstanceCommand(int InstanceId);
|
||||
/// <see cref="SetConnectionBindingsCommand"/>. This is a named record (not a
|
||||
/// <c>ValueTuple</c>) so it serializes with stable, named JSON properties and can
|
||||
/// evolve additively per REQ-COM-5a.
|
||||
/// <para>
|
||||
/// <c>DataSourceReferenceOverride</c> is an optional per-instance override of
|
||||
/// the OPC UA node id (or other protocol address) for the bound attribute.
|
||||
/// When non-null it replaces the template's <c>DataSourceReference</c> at
|
||||
/// flattening time; when null the template default is used.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public record ConnectionBinding(string AttributeName, int DataConnectionId);
|
||||
public record ConnectionBinding(
|
||||
string AttributeName,
|
||||
int DataConnectionId,
|
||||
string? DataSourceReferenceOverride = null);
|
||||
|
||||
public record SetConnectionBindingsCommand(int InstanceId, IReadOnlyList<ConnectionBinding> Bindings);
|
||||
public record SetInstanceOverridesCommand(int InstanceId, IReadOnlyDictionary<string, string?> Overrides);
|
||||
|
||||
@@ -330,20 +330,22 @@ public class InstanceService
|
||||
|
||||
var results = new List<InstanceConnectionBinding>();
|
||||
|
||||
foreach (var (attrName, connId) in bindings)
|
||||
foreach (var b in bindings)
|
||||
{
|
||||
if (existingMap.TryGetValue(attrName, out var existing))
|
||||
if (existingMap.TryGetValue(b.AttributeName, out var existing))
|
||||
{
|
||||
existing.DataConnectionId = connId;
|
||||
existing.DataConnectionId = b.DataConnectionId;
|
||||
existing.DataSourceReferenceOverride = b.DataSourceReferenceOverride;
|
||||
await _repository.UpdateInstanceConnectionBindingAsync(existing, cancellationToken);
|
||||
results.Add(existing);
|
||||
}
|
||||
else
|
||||
{
|
||||
var binding = new InstanceConnectionBinding(attrName)
|
||||
var binding = new InstanceConnectionBinding(b.AttributeName)
|
||||
{
|
||||
InstanceId = instanceId,
|
||||
DataConnectionId = connId
|
||||
DataConnectionId = b.DataConnectionId,
|
||||
DataSourceReferenceOverride = b.DataSourceReferenceOverride
|
||||
};
|
||||
await _repository.AddInstanceConnectionBindingAsync(binding, cancellationToken);
|
||||
results.Add(binding);
|
||||
|
||||
+28
@@ -51,4 +51,32 @@ public class ConnectionBindingSerializationTests
|
||||
// ConnectionBinding is a record: each element compares by value.
|
||||
Assert.Equal(original.Bindings, deserialized.Bindings);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Roundtrip_preserves_override_when_set()
|
||||
{
|
||||
var original = new ConnectionBinding("Speed", 7, "ns=2;s=Pump1.Speed");
|
||||
|
||||
var json = JsonSerializer.Serialize(original);
|
||||
var roundtripped = JsonSerializer.Deserialize<ConnectionBinding>(json);
|
||||
|
||||
Assert.NotNull(roundtripped);
|
||||
Assert.Equal(original, roundtripped);
|
||||
Assert.Equal("ns=2;s=Pump1.Speed", roundtripped!.DataSourceReferenceOverride);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Roundtrip_defaults_override_to_null_when_absent()
|
||||
{
|
||||
// Older site builds will not emit the new field — deserialization
|
||||
// must produce a null override and equal an explicit-null instance.
|
||||
const string legacyJson = """{"AttributeName":"Speed","DataConnectionId":7}""";
|
||||
|
||||
var deserialized = JsonSerializer.Deserialize<ConnectionBinding>(legacyJson);
|
||||
|
||||
Assert.NotNull(deserialized);
|
||||
Assert.Equal("Speed", deserialized!.AttributeName);
|
||||
Assert.Equal(7, deserialized.DataConnectionId);
|
||||
Assert.Null(deserialized.DataSourceReferenceOverride);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user