node-opcua-service-filter 2.74.0 → 2.76.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/check_event_clause.d.ts +17 -0
  2. package/dist/check_event_clause.js +52 -0
  3. package/dist/check_event_clause.js.map +1 -0
  4. package/dist/check_where_clause.d.ts +3 -0
  5. package/dist/check_where_clause.js +250 -0
  6. package/dist/check_where_clause.js.map +1 -0
  7. package/dist/extract_event_field.d.ts +9 -0
  8. package/dist/extract_event_field.js +53 -0
  9. package/dist/extract_event_field.js.map +1 -0
  10. package/dist/filter_context.d.ts +11 -0
  11. package/dist/filter_context.js +3 -0
  12. package/dist/filter_context.js.map +1 -0
  13. package/dist/index.d.ts +8 -0
  14. package/dist/index.js +8 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/make_content_filter.d.ts +22 -0
  17. package/dist/make_content_filter.js +121 -0
  18. package/dist/make_content_filter.js.map +1 -0
  19. package/dist/on_address_space/extract_event_fields.d.ts +10 -0
  20. package/dist/on_address_space/extract_event_fields.js +18 -0
  21. package/dist/on_address_space/extract_event_fields.js.map +1 -0
  22. package/dist/on_address_space/filter_context_on_address_space.d.ts +19 -0
  23. package/dist/on_address_space/filter_context_on_address_space.js +109 -0
  24. package/dist/on_address_space/filter_context_on_address_space.js.map +1 -0
  25. package/dist/on_address_space/index.d.ts +2 -0
  26. package/dist/on_address_space/index.js +19 -0
  27. package/dist/on_address_space/index.js.map +1 -0
  28. package/dist/resolve_operand.d.ts +4 -0
  29. package/dist/resolve_operand.js +45 -0
  30. package/dist/resolve_operand.js.map +1 -0
  31. package/dist/tools_event_filter.d.ts +4 -16
  32. package/dist/tools_event_filter.js +53 -121
  33. package/dist/tools_event_filter.js.map +1 -1
  34. package/package.json +16 -15
  35. package/source/check_event_clause.ts +54 -0
  36. package/source/check_where_clause.ts +287 -0
  37. package/source/extract_event_field.ts +55 -0
  38. package/source/filter_context.ts +15 -0
  39. package/source/index.ts +8 -0
  40. package/source/make_content_filter.ts +132 -0
  41. package/source/on_address_space/extract_event_fields.ts +24 -0
  42. package/source/on_address_space/filter_context_on_address_space.ts +134 -0
  43. package/source/on_address_space/index.ts +3 -0
  44. package/source/resolve_operand.ts +45 -0
  45. package/source/tools_event_filter.ts +61 -129
@@ -0,0 +1,45 @@
1
+ import { NodeClass } from "node-opcua-data-model";
2
+ import { make_warningLog } from "node-opcua-debug";
3
+ import { NodeId } from "node-opcua-nodeid";
4
+ import { constructBrowsePathFromQualifiedName, makeBrowsePath } from "node-opcua-service-translate-browse-path";
5
+ import { StatusCodes } from "node-opcua-status-code";
6
+ import { SimpleAttributeOperand, AttributeOperand, VariableAttributes } from "node-opcua-types";
7
+ import { DataType, Variant } from "node-opcua-variant";
8
+ import { FilterContext } from "./filter_context";
9
+
10
+ const warningLog = make_warningLog("FILTER");
11
+
12
+ // export function readOperand(context: FilterContext, operand: SimpleAttributeOperand): Variant {
13
+ // // navigate to the innerNode specified by the browsePath [ QualifiedName]
14
+ // const browsePath = constructBrowsePathFromQualifiedName({ nodeId: context.eventSource }, operand.browsePath);
15
+ // const targetNode = context.browsePath(browsePath);
16
+ // if (!targetNode) {
17
+ // return new Variant({ dataType: DataType.Null });
18
+ // }
19
+ // return context.readNodeValue(targetNode);
20
+ // }
21
+
22
+ export function resolveOperand(context: FilterContext, operand: SimpleAttributeOperand | AttributeOperand): Variant {
23
+ if (operand instanceof SimpleAttributeOperand) {
24
+ const browsePath = constructBrowsePathFromQualifiedName({ nodeId: context.eventSource }, operand.browsePath);
25
+
26
+ const target: NodeId | null = context.browsePath(browsePath);
27
+ if (!target) {
28
+ return new Variant({ dataType: DataType.Null });
29
+ // return new Variant({ dataType: DataType.StatusCode, value: StatusCodes.BadNodeIdUnknown });
30
+ }
31
+ const nodeClass = context.getNodeClass(target);
32
+ if (nodeClass !== NodeClass.Variable) {
33
+ warningLog("resolveOperand: cannot find variable here but got nodeClass", NodeClass[nodeClass], browsePath.toString());
34
+ return new Variant({ dataType: DataType.StatusCode, value: StatusCodes.BadNodeClassInvalid });
35
+ }
36
+ const value = context.readNodeValue(target);
37
+ return value;
38
+ } else {
39
+ if (!(operand instanceof AttributeOperand)) {
40
+ throw new Error("expecting an AttributeOperand");
41
+ }
42
+ warningLog("AttributeOperand is not yet implemented");
43
+ return new Variant({ dataType: DataType.Null });
44
+ }
45
+ }
@@ -1,168 +1,100 @@
1
1
  /**
2
2
  * @module node-opcua-service-filter
3
3
  */
4
- // tslint:disable:object-literal-shorthand
5
- // tslint:disable:only-arrow-functions
6
- // tslint:disable:max-line-length
7
-
8
- import { assert } from "node-opcua-assert";
9
4
  import { ObjectTypeIds } from "node-opcua-constants";
10
- import { AttributeIds, stringToQualifiedName } from "node-opcua-data-model";
11
- import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
12
- import { makeNodeId, NodeId, resolveNodeId, sameNodeId } from "node-opcua-nodeid";
13
- import { DataType, Variant } from "node-opcua-variant";
5
+ import { AttributeIds, QualifiedName, stringToQualifiedName } from "node-opcua-data-model";
6
+ import { NodeIdLike, resolveNodeId } from "node-opcua-nodeid";
14
7
 
15
- import { EventFilter, SimpleAttributeOperand } from "./imports";
8
+ import { ContentFilter, ContentFilterElement, ContentFilterOptions, EventFilter, FilterOperator, SimpleAttributeOperand } from "./imports";
16
9
 
17
- const debugLog = make_debugLog(__filename);
18
- const doDebug = checkDebugFlag(__filename);
10
+ import { ofType } from "./make_content_filter";
19
11
 
20
- /**
21
- * helper to construct event filters:
22
- * construct a simple event filter
23
- *
24
- *
25
- * @example
26
- *
27
- * constructEventFilter(["SourceName","Message","ReceiveTime"]);
28
- *
29
- * constructEventFilter(["SourceName",{namespaceIndex:2 , "MyData"}]);
30
- * constructEventFilter(["SourceName","2:MyData" ]);
31
- *
32
- * constructEventFilter(["SourceName" ,["EnabledState","EffectiveDisplayName"] ]);
33
- * constructEventFilter(["SourceName" ,"EnabledState.EffectiveDisplayName" ]);
34
- *
35
- */
36
- export function constructEventFilter(arrayOfNames: string[] | string, conditionTypes?: NodeId[] | NodeId): EventFilter {
12
+ export function constructSelectClause(arrayOfNames: string | string[]): SimpleAttributeOperand[] {
37
13
  if (!Array.isArray(arrayOfNames)) {
38
- return constructEventFilter([arrayOfNames], conditionTypes);
39
- }
40
- if (conditionTypes && !Array.isArray(conditionTypes)) {
41
- return constructEventFilter(arrayOfNames, [conditionTypes]);
42
- }
43
- // istanbul ignore next
44
- if (!(arrayOfNames instanceof Array)) {
45
- throw new Error("internal error");
14
+ return constructSelectClause([arrayOfNames]);
46
15
  }
16
+
47
17
  // replace "string" element in the form A.B.C into [ "A","B","C"]
48
- const arrayOfNames2 = arrayOfNames.map((path) => {
49
- if (typeof path !== "string") {
50
- return path;
51
- }
52
- return path.split(".");
53
- });
18
+ const arrayOfNames2 = arrayOfNames.map((path) => (typeof path !== "string" ? path : path.split(".")));
19
+
20
+ const arrayOfNames3 = arrayOfNames2.map((path) => (Array.isArray(path) ? path.map(stringToQualifiedName) : path));
54
21
 
55
- const arrayOfNames3 = arrayOfNames2.map((path) => {
56
- if (Array.isArray(path)) {
57
- return path.map(stringToQualifiedName);
58
- }
59
- return path;
60
- });
61
22
  // replace "string" elements in arrayOfName with QualifiedName in namespace 0
62
- const arrayOfNames4 = arrayOfNames3.map((s) => {
63
- return typeof s === "string" ? stringToQualifiedName(s) : s;
64
- });
23
+ const arrayOfNames4 = arrayOfNames3.map((s) => (typeof s === "string" ? stringToQualifiedName(s) : s));
65
24
 
66
25
  // construct browse paths array
67
- const browsePaths = arrayOfNames4.map((s) => {
68
- return Array.isArray(s) ? s : [s];
69
- });
26
+ const browsePaths = arrayOfNames4.map((s) => (Array.isArray(s) ? s : [s]));
70
27
 
71
28
  // Part 4 page 127:
72
29
  // In some cases the same BrowsePath will apply to multiple EventTypes. If the Client specifies the BaseEventType
73
30
  // in the SimpleAttributeOperand then the Server shall evaluate the BrowsePath without considering the Type.
74
31
 
32
+ const isBrowsePathForConditionId = (browsePath: QualifiedName[]) =>
33
+ browsePath.length === 1 && browsePath[0].namespaceIndex === 0 && browsePath[0].name === "ConditionId";
34
+
75
35
  // [..]
76
36
  // The SimpleAttributeOperand structure allows the Client to specify any Attribute, however, the Server is only
77
37
  // required to support the Value Attribute for Variable Nodes and the NodeId Attribute for Object Nodes.
78
38
  // That said, profiles defined in Part 7 may make support for additional Attributes mandatory.
79
- let selectClauses = browsePaths.map((browsePath) => {
80
- return new SimpleAttributeOperand({
81
- attributeId: AttributeIds.Value,
82
- browsePath,
83
- indexRange: undefined, // NumericRange
84
- typeDefinitionId: makeNodeId(ObjectTypeIds.BaseEventType) // i=2041
85
- });
86
- });
87
-
88
- if (conditionTypes && conditionTypes instanceof Array) {
89
- const extraSelectClauses = conditionTypes.map((nodeId) => {
39
+ const selectClauses = browsePaths.map((browsePath: QualifiedName[]) => {
40
+ if (isBrowsePathForConditionId(browsePath)) {
41
+ // special case
42
+ //
43
+ // The NodeId of the Condition instance is used as ConditionId. It is not explicitly modelled as a
44
+ // component of the ConditionType. However, it can be requested with the following
45
+ // SimpleAttributeOperand (see Table 10) in the SelectClause of the EventFilter:
46
+ //
47
+ // SimpleAttributeOperand
48
+ // Name Type Description
49
+ // typeId NodeId NodeId of the ConditionType Node
50
+ // browsePath[] QualifiedName empty
51
+ // attributeId IntegerId Id of the NodeId Attribute
52
+ //
90
53
  return new SimpleAttributeOperand({
91
54
  attributeId: AttributeIds.NodeId,
92
- browsePath: undefined,
55
+ browsePath: null,
93
56
  indexRange: undefined, // NumericRange
94
- typeDefinitionId: nodeId // conditionType for instance
57
+ typeDefinitionId: ObjectTypeIds.ConditionType // i=2782
58
+ });
59
+ } else
60
+ return new SimpleAttributeOperand({
61
+ attributeId: AttributeIds.Value,
62
+ browsePath,
63
+ indexRange: undefined, // NumericRange
64
+ typeDefinitionId: ObjectTypeIds.BaseEventType // i=2041
95
65
  });
96
- });
97
- selectClauses = selectClauses.concat(extraSelectClauses);
98
- }
99
-
100
- const filter = new EventFilter({
101
- selectClauses,
102
- whereClause: {
103
- // ContentFilter
104
- elements: [
105
- // ContentFilterElement
106
- // {
107
- // filterOperator: FilterOperator.IsNull,
108
- // filterOperands: [ //
109
- // new ElementOperand({
110
- // index: 123
111
- // }),
112
- // new AttributeOperand({
113
- // nodeId: "i=10",
114
- // alias: "someText",
115
- // browsePath: { //RelativePath
116
- //
117
- // },
118
- // attributeId: AttributeIds.Value
119
- // })
120
- // ]
121
- // }
122
- ]
123
- }
124
66
  });
125
- return filter;
67
+ return selectClauses;
126
68
  }
127
-
128
69
  /**
129
- * @class SimpleAttributeOperand
130
- * @method toPath
131
- * @return {String}
70
+ * helper to construct event filters:
71
+ * construct a simple event filter
132
72
  *
133
- * @example:
73
+ * "ConditionId" in the arrayOfNames has a special meaning
134
74
  *
75
+ * @example
135
76
  *
136
- */
137
- function simpleAttributeOperandToPath(self: SimpleAttributeOperand): string {
138
- if (!self.browsePath) {
139
- return "";
140
- }
141
- return self.browsePath
142
- .map((a) => {
143
- return a.name;
144
- })
145
- .join("/");
146
- }
147
-
148
- /**
149
- * @class SimpleAttributeOperand
150
- * @method toShortString
151
- * @return {String}
77
+ * constructEventFilter(["SourceName","Message","ReceiveTime"]);
152
78
  *
153
- * @example:
79
+ * constructEventFilter(["SourceName",{namespaceIndex:2 , "MyData"}]);
80
+ * constructEventFilter(["SourceName","2:MyData" ]);
154
81
  *
82
+ * constructEventFilter(["SourceName" ,["EnabledState","EffectiveDisplayName"] ]);
83
+ * constructEventFilter(["SourceName" ,"EnabledState.EffectiveDisplayName" ]);
155
84
  *
156
85
  */
157
- export function simpleAttributeOperandToShortString(
158
- self: SimpleAttributeOperand,
159
- addressSpace: any // Address Space
160
- ): string {
161
- let str = "";
162
- if (addressSpace) {
163
- const n = addressSpace.findNode(self.typeDefinitionId)!;
164
- str += n.BrowseName.toString();
86
+ export function constructEventFilter(
87
+ arrayOfNames: string[] | string,
88
+ whereClause?: ContentFilterOptions | ContentFilterElement
89
+ ): EventFilter {
90
+ const selectClauses = constructSelectClause(arrayOfNames);
91
+
92
+ if (whereClause instanceof ContentFilterElement) {
93
+ whereClause = new ContentFilter({ elements: [whereClause] });
165
94
  }
166
- str += "[" + self.typeDefinitionId.toString() + "]" + simpleAttributeOperandToPath(self);
167
- return str;
95
+ const filter = new EventFilter({
96
+ selectClauses,
97
+ whereClause
98
+ });
99
+ return filter;
168
100
  }