opa icon indicating copy to clipboard operation
opa copied to clipboard

Proposal: add elipsis matching for arrays

Open srenatus opened this issue 6 years ago • 5 comments

When we want to match each of these paths,

path1 = ["root", "private"]
path2 = ["root", "private", "foo"]
path3 = ["root", "private", "foo", "bar"]
path4 = ["root", "public"]

and only care for them to start with ["root", "private"], it would me nice if we could say

input.path == ["root", "private", ...]

and had it match all of path1, path2, and path3.

Right now, we have to explicitly state

input.path[0] == "root"
input.path[1] == "private"

to make it match those three paths.

srenatus avatar Oct 02 '19 18:10 srenatus

This can be helped with, a little, by a helper definition:

path_prefix := {q | q := array.slice(input.path, 0, j + 1); input.path[j]}

This lets then use

path_prefix[["root", "private"]]

where we'd have liked to match with ["root", "private", ...], and it also allows for variables in the array:

> path_prefix := {q | q := array.slice(input.path, 0, j + 1); input.path[j]}
Rule 'path_prefix' defined in package repl. Type 'show' to see rules.
> path_prefix with input.path as ["foo", "bar", "baz"]
[
  [
    "foo"
  ],
  [
    "foo",
    "bar"
  ],
  [
    "foo",
    "bar",
    "baz"
  ]
]
> path_prefix[[x, "bar", y]] with input.path as ["foo", "bar", "baz"]
+-------+-------+--------------------------------+
|   x   |   y   |   path_prefix[[x, "bar", y]]   |
|       |       |   with input.path as ["foo",   |
|       |       |         "bar", "baz"]          |
+-------+-------+--------------------------------+
| "foo" | "baz" | ["foo","bar","baz"]            |
+-------+-------+--------------------------------+
>

srenatus avatar Jul 09 '20 14:07 srenatus

While I like this, is there something this provides more than what is shown in the example here?
It feels like this would just as well be improved by a a more succint way of expressing array slices, like e.g. Python provides:

input.path == ["root", "private", ...]

could be:

input.path[:2] == ["root", "private"]

Having a more powerful way of expressing array slices would have quite a few more benefits, like slicing from the end of the array, providing a custom step value, etc.

anderseknert avatar Jan 16 '22 20:01 anderseknert

Discussing this with @srenatus, it would be pretty neat if an elipsis operator would encompass objects as well, so you could do object destructuring like:

some {"name": name, "permissions": permissions, ...} in input.user.attributes

And perhaps it could be used to match parts of an object as well:

{"a: 1, "b": 2, ...} == {"a": 1, "b": 2, "c": 3}

anderseknert avatar Jan 17 '22 13:01 anderseknert

@johanfylling had an interesting case for this, where he wanted to do pattern matching for "last in path" without knowing the length of the array, e.g. something like

walk(object, [[..., "modules"], value])

anderseknert avatar Feb 14 '23 12:02 anderseknert

I could also see the elipsis operator being useful for referencing documents at arbitrarily deep paths for dynamic composition... for example:

data.acme[path...].allow

tsandall avatar Aug 18 '23 21:08 tsandall