Skip to content

Commit

Permalink
- improved nested list management
Browse files Browse the repository at this point in the history
  • Loading branch information
tkobayas committed Oct 28, 2024
1 parent ae1d898 commit 61b51a6
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -825,4 +825,130 @@ public void testSelectAttrForArrayInArrayWithIndex() {

rulesExecutor.dispose();
}

@Test
public void testSelectAttrForArrayInArrayInArray() {

String JSON_ARRAY_IN_ARRAY =
"""
{
"rules":[
{
"Rule":{
"name":"r1",
"condition":{
"AllCondition":[
{
"SelectAttrExpression":{
"lhs":{
"Event":"incident.alerts.tags.messages"
},
"rhs":{
"key":{
"String":"value"
},
"operator":{
"String":"=="
},
"value":{
"String":"DiskUsage"
}
}
}
}
]
},
"actions":[
{
"Action":{
"action":"debug",
"action_args":{
"msg":"Found a match with alerts"
}
}
}
],
"enabled":true
}
}
]
}
""";

RulesExecutor rulesExecutor = RulesExecutorFactory.createFromJson(JSON_ARRAY_IN_ARRAY);

List<Match> matchedRules = rulesExecutor.processFacts( """
{
"incident":{
"id":"aaa",
"active":false,
"alerts":[
{
"id":"bbb",
"tags":[
{
"messages":[
{
"name":"alertname",
"value":"MariadbDown"
},
{
"name":"severity",
"value":"critical"
}
]
},
{
"messages":[
{
"name":"severity",
"value":"low"
},
{
"name":"notification",
"value":"access"
}
]
}
],
"status":"Ok"
},
{
"id":"ccc",
"tags":[
{
"messages":[
{
"name":"severity",
"value":"critical"
},
{
"name":"alertname",
"value":"DiskUsage"
}
]
},
{
"messages":[
{
"name":"severity",
"value":"low"
},
{
"name":"notification",
"value":"access"
}
]
}
],
"status":"Ok"
}
]
}
}
""" ).join();
assertEquals( 1, matchedRules.size() );

rulesExecutor.dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ public Object visit(ExtractorNode n) {
if (this.cur == null || this.cur == Prototype.UNDEFINED_VALUE) {
break;
}
if (this.cur instanceof PathWrapperList) {
List<Object> nextNodeList = new PathWrapperList();
for (Object element : (List<?>) this.cur) {
if (this.cur instanceof PathWrapperList currentNodeList) {
PathWrapperList nextNodeList = new PathWrapperList();
// Apply extraction to all paths in the list
for (Object element : currentNodeList) {
this.cur = element;
Object nextNode = chunk.accept(this);
if (nextNode != Prototype.UNDEFINED_VALUE) {
Expand All @@ -106,24 +107,45 @@ public Object visit(ExtractorNode n) {
if (nextNodeList.isEmpty()) {
this.cur = Prototype.UNDEFINED_VALUE;
} else {
// Flatten PathWrapperList if nested
nextNodeList = flattenPathWrapperList(nextNodeList);
this.cur = nextNodeList;
}
} else {
this.cur = chunk.accept(this);
}
}
if (cur instanceof List) {
cur = flatten((List<?>) cur);
}

// At this point, cur is wrapped in one PathWrapperList at most
cur = stripPathWrapperListIfExists(cur);
return cur;
}

public static List<Object> flatten(List<?> nestedList) {
return nestedList.stream()
.flatMap(element -> element instanceof List<?>
? flatten((List<?>) element).stream()
: List.of(element).stream())
.toList();
private PathWrapperList flattenPathWrapperList(PathWrapperList pathWrapperList) {
PathWrapperList flattenedList = new PathWrapperList();
for (Object element : pathWrapperList) {
if (element instanceof PathWrapperList nestedPathWrapperList) {
flattenedList.addAll(nestedPathWrapperList); // nest is at most one level deep
} else {
flattenedList.add(element);
}
}
return flattenedList;
}

private static Object stripPathWrapperListIfExists(Object current) {
if (current instanceof PathWrapperList pathWrapperList) {
if (pathWrapperList.isEmpty()) {
return Prototype.UNDEFINED_VALUE;
}
// if the elements are lists, flatten them
// if not, collect them in a list
return pathWrapperList.stream()
.flatMap(e -> e instanceof List list ? list.stream() : List.of(e).stream())
.toList();
} else {
return current;
}
}

// This List is used to wrap the node paths when the path indicates all elements of an array
Expand Down

0 comments on commit 61b51a6

Please sign in to comment.