Picking the first value you find from 2 objects in Rego

Monday, September 30, 2019

This post is about "how you can pick the first value you find from 2 objects" in Rego, a query language used in OPA (Open Policy Agent).

This use case is a little confusing and you'll probably think "When is this necessary?". One example is shared in "Merge Objects" in the official docs.

When merging multiple objects, you'll definitely need to think about colliding keys and how to decide which key , value to choose. This is where you'll want to use "Pick the first value you find from 2 objects".

Let's dive into details.

Logical OR in Rego

The function which "Picks the first value it finds from 2 objects" will be called pick_first . Here's how the implementation will look like.

has_key(x, k) { 
    _ := x[k]
}

pick_first(k, a, b) = a[k]
pick_first(k, a, b) = b[k] { not has_key(a, k) }

See how there are 2 definitions of pick_first(k, a, b) . This is how you express a Logical OR in Rego. So the expression above is like saying:

"For key k , choose the value from object a , OR, choose the value from object b if object aDOES NOT HAVE key k ."

If you feel uncomfortable with the has_key function, look at my previous post specifically explaining about it here:

Example

Here's a complete example demonstrating the usage of pick_first .

has_key(x, k) { 
    _ := x[k]
}

pick_first(k, a, b) = a[k]
pick_first(k, a, b) = b[k] { not has_key(a, k) }

x := {"a": true, "b": false}
y := {"b": "foo", "c": 4}

first_values = fv {
    a := pick_first("a", x, y)
    b := pick_first("b", x, y)
    c := pick_first("c", x, y)
    fv := {
        "a": a,
        "b": b,
        "c": c
    }
}

If you evaluate first_values , the result would be:

{
  "a": true,
  "b": false,
  "c": 4
}

Notice how key false was chosen from object x 's key b . The only time the values of object y are selected are when the key doesn't exist in object x (e.g. key c ).

You can check this out for yourself in the following playground:

https://play.openpolicyagent.org/p/puwMTreKjD

Reference

This post is also available on DEV.