Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions policy/src/main/java/dev/cel/policy/RuleComposer.java
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,12 @@ private Step optimizeRule(Cel cel, CelCompiledRule compiledRule, boolean asList)

private @Nullable Step createBaseStep(boolean returnList, boolean hasOptionalOutput) {
if (returnList) {
// If the rule is evaluated as a list (AGGREGATE), the base case is an empty list.
return Step.newUnconditionalNonOptionalStep(newTrueLiteral(), newList());
if (hasOptionalOutput) {
// If a nested rule inside an aggregate context has an optional output, the last result in
// the ternary should return an empty list to allow concatenation with other branches.
return Step.newUnconditionalNonOptionalStep(newTrueLiteral(), newList());
}
return null;
}

if (hasOptionalOutput) {
Expand Down Expand Up @@ -280,6 +284,10 @@ private Step combineAggregate(AstMutator astMutator, Step currentStep, Step accu
conditionalListPart = currentListPart;
}

if (accumulatedStep == null) {
return Step.newUnconditionalNonOptionalStep(trueCondition, conditionalListPart);
}

CelMutableAst concatenated =
astMutator.newGlobalCall(
Operator.ADD.getFunction(), conditionalListPart, accumulatedStep.expr);
Expand Down
58 changes: 56 additions & 2 deletions policy/src/test/java/dev/cel/policy/CelPolicyCompilerImplTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,62 @@ public void compileYamlPolicy_aggregate_macrosPreserved() throws Exception {
String unparsed = CelUnparserFactory.newUnparser().unparse(ast);
assertThat(unparsed)
.isEqualTo(
"(cond ? [payload.filter(x, x > 10, x).exists(y, y % 2 == 0)] : []) "
+ "+ ([payload.all(x, x > 0)] + [])");
"(cond ? [payload.filter(x, x > 10).exists(y, y % 2 == 0)] : []) "
+ "+ [payload.all(x, x > 0)]");
}

@Test
public void compileYamlPolicy_aggregateSingleMatch_noSuperfluousConcatenation() throws Exception {
String policySource =
"name: aggregate_single_match\n"
+ "rule:\n"
+ " aggregate:\n"
+ " - condition: \"cond\"\n"
+ " output: \"payload.filter(x, x > 10).exists(y, y % 2 == 0)\"\n";
Cel cel =
newCel()
.toCelBuilder()
.addVar("cond", SimpleType.BOOL)
.addVar("payload", ListType.create(SimpleType.INT))
.build();

CelPolicy policy = POLICY_PARSER.parse(policySource);

CelAbstractSyntaxTree ast =
CelPolicyCompilerFactory.newPolicyCompiler(cel).build().compile(policy);

String unparsed = CelUnparserFactory.newUnparser().unparse(ast);
assertThat(unparsed).isEqualTo("cond ? [payload.filter(x, x > 10).exists(y, y % 2 == 0)] : []");
}

@Test
public void compileYamlPolicy_aggregateMultipleConditionalMatches_noSuperfluousConcatenation()
throws Exception {
String policySource =
"name: aggregate_multiple_conditional\n"
+ "rule:\n"
+ " aggregate:\n"
+ " - condition: \"cond1\"\n"
+ " output: \"payload.all(x, x > 0)\"\n"
+ " - condition: \"cond2\"\n"
+ " output: \"payload.exists(x, x == 0)\"\n";
Cel cel =
newCel()
.toCelBuilder()
.addVar("cond1", SimpleType.BOOL)
.addVar("cond2", SimpleType.BOOL)
.addVar("payload", ListType.create(SimpleType.INT))
.build();

CelPolicy policy = POLICY_PARSER.parse(policySource);

CelAbstractSyntaxTree ast =
CelPolicyCompilerFactory.newPolicyCompiler(cel).build().compile(policy);

String unparsed = CelUnparserFactory.newUnparser().unparse(ast);
assertThat(unparsed)
.isEqualTo(
"(cond1 ? [payload.all(x, x > 0)] : []) + (cond2 ? [payload.exists(x, x == 0)] : [])");
}

@Test
Expand Down
Loading