OR in Open Policy Agent (union behavior)
Asked Answered
Z

2

8

In OPA it's clear how to query against condition AND condition:

values := {
  "value1": {
    "a": "one"
  },
  "value2": {
    "a": "one",
    "b": "two"
  },
  "value3": {
    "a": "one",
    "b": "one"
  }
}

goodValues = [name |
  value = values[name]
  value.a == "one"
  value.b == "one"
]

So that goodValues here will contain value3 only.

But how to query condition OR condition, so that goodValues will contain all 3 values, because they have either value.a == "one" OR value.b == "one"?

Zygapophysis answered 10/10, 2019 at 1:28 Comment(0)
P
16

Joining multiple expressions together expresses logical AND. To express logical OR you define multiple rules or functions with the same name. There are a couple different ways this can work. This is covered in the introduction to OPA: https://www.openpolicyagent.org/docs/latest/#logical-or.

Option 1: Comprehensions & Functions

The conditions that you want to express against the value can be factored into helper functions and then the comprehension query can refer to the function.

goodValues = [name |
  value := values[name]
  value_match(value)
]

value_match(v) {
  v.a == "one"
}

value_match(v) {
  v.b = "two"
}

Option 2: Incremental Rules

In OPA/Rego, incremental rules assign a set of values to a variable. The rule definition provides the logic to generate the set values. Unlike comprehensions, you can overload the rule definition (providing multiple with the same name) and express logical OR like the other answer explains.

# goodValues is a set that contains 'name' if...
goodValues[name] {
 value := values[name]  # name is in values
 value.a == "one"       # value.a is "one"
}

# goodvalues is a set that contains 'name' if...
goodValues[name] {
  value := values[name]  # name is in values
  value.b == "two"       # value.b is "two"
}
Paramorph answered 10/10, 2019 at 15:4 Comment(1)
in Option 1 how does it even work? the helper functions have the same nameMusick
Z
1

Found an ugly answer so far, via incremental set:

goodValues[name] {
  value = values[name]
  value.a == "one"
}

goodValues[name] {
  value = values[name]
  value.b == "one"
}

But what if that common condition value = values[name] gets more complicated? Will need to extract it to a separate variable (and iterate over that in every condition statement)? Any better solution?

Zygapophysis answered 10/10, 2019 at 1:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.