feat(opcua): HistoryReadEvents projects EventType, ConditionName, SourceNode; honours the where-clause (lmxopcua#746)
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
This commit is contained in:
+15
-1
@@ -585,7 +585,21 @@ owns at least one alarm condition is already an event notifier; the server regis
|
||||
HistorianGateway using that source. (Alarm-history `ReadEvents` requires the gateway running
|
||||
`RuntimeDb:EventReadsEnabled=true`.) Event-field projection supports the standard
|
||||
`BaseEventType` select clauses — `EventId`, `SourceName`, `Time`, `ReceiveTime`, `Message`,
|
||||
and `Severity`; an unsupported select operand returns a null field (spec-conformant).
|
||||
`Severity` — plus (client-visible: these used to be null):
|
||||
|
||||
- **`EventType`** — the stored alarm type name mapped to its Part 9 type (`LimitAlarm` ⇒ `LimitAlarmType`, `OffNormalAlarm` ⇒
|
||||
`OffNormalAlarmType`, `DiscreteAlarm` ⇒ `DiscreteAlarmType`, `AlarmCondition` ⇒ `AlarmConditionType`); a row with no type
|
||||
name, or one that is not an event type, is `AlarmConditionType` (every historical row is alarm history).
|
||||
- **`ConditionName`** — the stored alarm name.
|
||||
- **`SourceNode`** — the condition node the stored alarm id names (a native alarm's RawPath, a scripted alarm's id), the same
|
||||
`SourceNode` live condition events carry; null when that condition is not materialised on this node now.
|
||||
|
||||
Every backend stores the three (SqlServer `AlarmTypeName` / `AlarmName` / `AlarmId`, QuestDB `alarm_type_name` /
|
||||
`alarm_name` / `alarm_id`, Gateway the event `Type` and its `AlarmName` / `AlarmId` properties). **The where-clause is
|
||||
honoured:** each event is evaluated against it with the SDK's content filter — `OfType` through the server's type tree (a
|
||||
supertype keeps its subtypes), any other operator against the projected fields. Filtering happens after a page's
|
||||
continuation point is taken from the unfiltered page, so paging is unchanged: a filtered page may hold fewer events (even
|
||||
none) and still carry a continuation point. An unsupported select operand returns a null field (spec-conformant).
|
||||
|
||||
### No driver-side history (Gitea #655)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user