29665c1872
HistoryReadEvents projected only EventId / SourceName / Time / ReceiveTime / Message / Severity: a select clause asking for EventType, ConditionName or SourceNode (what most generic alarm viewers ask for) got nulls, and the event filter's where-clause (an OfType) was ignored. - HistoricalEvent gains optional EventTypeName, ConditionName and AlarmId. SqlServer, QuestDB and Gateway event reads fill them from what their alarm writers already store (AlarmTypeName / AlarmName / AlarmId; the gateway event Type and its AlarmName / AlarmId properties). - The node manager maps the type name to its Part 9 event type (unknown or non-event => AlarmConditionType), projects ConditionName, and resolves SourceNode to the materialised condition the alarm id names (the live events' SourceNode), else null. - The where-clause is evaluated per event with the SDK content filter through an IFilterTarget (OfType via the type tree; other operators against the projected fields), after the page's cursor is taken, so paging is unchanged. Tested in the node manager, over a real client session (the Client.CLI has no `historyread --events` mode yet; filed as a follow-up), and by alarm writer -> event read round trips on SqlServer and QuestDB. Rebased from the unpushed remed/lane-H2 branch (originally authored 2026-10-22 in session_01Ub9hGmYLQvn9XETzw7CMsT) onto current master. Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
16 lines
863 B
C#
16 lines
863 B
C#
namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Sql.Common;
|
|
|
|
/// <summary>Helpers for turning stored event rows into <c>HistoricalEvent</c>s.</summary>
|
|
public static class HistoricalEventRows
|
|
{
|
|
/// <summary>Clamps a stored severity into the <see cref="ushort"/> range the event carries.</summary>
|
|
/// <param name="severity">Stored severity.</param>
|
|
/// <returns>The severity clamped to 0..65535.</returns>
|
|
public static ushort ClampSeverity(int severity) => (ushort)Math.Clamp(severity, 0, ushort.MaxValue);
|
|
|
|
/// <summary>A stored optional text column as the event carries it: empty (the writers' "none") is null.</summary>
|
|
/// <param name="value">The stored text.</param>
|
|
/// <returns>The text, or null when empty or absent.</returns>
|
|
public static string? NullIfEmpty(string? value) => string.IsNullOrEmpty(value) ? null : value;
|
|
}
|