Skip to content

Provide built-in function to help sort composite values #7445

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
anderseknert opened this issue Mar 12, 2025 · 5 comments
Open

Provide built-in function to help sort composite values #7445

anderseknert opened this issue Mar 12, 2025 · 5 comments

Comments

@anderseknert
Copy link
Member

While we have the sort built-in function to sort a list of values by their "natural" order (as defined here) I have found that in the few cases where I've needed to sort a list of objects by the value of some key, that's really hard to do in Rego. A generic reduce function would make this easy for sure, but since that's been going nowhere, I propose we add a new built-in function to cover more than the most basic sorting needs.

Example code:

s := sort([
    {"b": 1, "t": 100}, 
    {"a": 1, "t": 50}, 
    {"c": 1, "t": 80},
])

This will sort the list in the order of the a, b and c keys, while what I need is to sort the list in the order of the t values (ascending/descending doesn't matter).

Extracting these values and having them sorted is of course trivial, but I'm not interested in sorting the values but the full objects based on those values.

There could be many ways to accomplish this, and discussion around the best approach would be great! But just to provide an example from a current built-in function, I could imagine something like the object.get semantics, where the collection is provided along with a path (or possibly multiple paths?) to use for sorting:

s := sort_by(
    [
        {"b": 1, "t": 100}, 
        {"a": 1, "t": 50}, 
        {"c": 1, "t": 80},
    ],
    ["t"]
)

Which would allow also for nested attributes to be used as sort keys. The function should accept either an array or a set, and always return an array. If an object in the collection doesn't have the sorting key(s), it could either be omitted from the result, or be an error/undefined.

@srenatus
Copy link
Contributor

Just a thought, we could mimic SQL:

s := sort_by(stuff, {
  "by": ["t", "s"], # optionally multiple things? i.e. sort by t first, then s
  "order": "desc", # or "asc"
  "limit": 10, # return top 10 only
  })

I might be overthinking this 😅

@anderseknert
Copy link
Member Author

No, I like it! I would prefer having an official / generic construct for LIMIT (and I think we have an issue open for that somewhere) but this would be a good start :) If we want to allow multiple sort keys, I guess we'd have to accept multiple arrays?

s := sort_by(stuff, {
    "by": [["foo", "bar"], ["bar", "baz"]],
    "order": "desc", # or "asc"
    "limit": 10, # return top 10 only
})

But that would make the common case (a single key) a little more annoying to type. Perhaps it could be "an array of strings or an array of arrays"

@srenatus
Copy link
Contributor

Why not go all-in?

Perhaps it could be "an array of strings or an array of arrays"

type example meaning
string "foo" sort by obj.foo
array ["foo", "bar"] sort by obj.foo.bar
array of arrays [["foo", "bar"], ["bar", "baz"]] sort by obj.foo.bar, then obj.bar.baz

the only thing that is awkward is that there's no simple way to say "sort by obj.foo, then obj.bar", that would be [["foo"], ["bar"]] 🤔

@anderseknert
Copy link
Member Author

That doesn't seem so awkward to me 🙂

Copy link

stale bot commented Apr 12, 2025

This issue has been automatically marked as inactive because it has not had any activity in the last 30 days. Although currently inactive, the issue could still be considered and actively worked on in the future. More details about the use-case this issue attempts to address, the value provided by completing it or possible solutions to resolve it would help to prioritize the issue.

@stale stale bot added the inactive label Apr 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants