Search code examples
open-policy-agentrego

How to convert a list to an object with key duplications in OPA Rego


I am new to Open Policy Agent (OPA) and Rego language. I need to convert a list of objects which I get from input to an object (in best case in O(n) time). The problem is that used key may be duplicated in a list. Input example:

[
    {
        "id": "a",
        "body": {...}
    },
    {
        "id": "b",
        "body": {...}
    },
    {
        "id": "a",
        "body": {...}
    }
]

Expected output:

{
    "a": [
        {
            "id": "a",
            "body": {...}
        },
        {
            "id": "a",
            "body": {...}
        }
    ],
    "b": [
        {
            "id": "b",
            "body": {...}
        }
    ]
}

What is the best option to do this? I tried to create a function, but output is never evaluated:

package test

inpt := [
    {"id": "a", "body":{"a":1}},
    {"id": "b", "body":{"a":1}},
    {"id": "a", "body":{"a":2}},
]

x := f(inpt)

f(input_list) = output_obj {
    output_obj := {}
    inner := input_list[_]
    inner_list = object.get(output_obj, inner.id, [])
    merged := array.concat(inner_list, [inner])
    output_obj[inner.id] = merged
}

The only option I found is inner loop (O(n^2)):

output_obj := {i.id : [j | j:= inpt[_]; j.id == i.id] | i := inpt[_]}

Solution

  • Comprehension indexing should ensure O(n) runtime complexity given the rule meets the conditions for that (which yours does):

    package test
    
    output_obj := {id: list |
        some i
        id := input[i].id
        list := [obj |
            some j
            input[j].id == id
            obj := input[j]
        ]
    }