-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Alter object.get builtin to support getting an array of nested keys from a nested object #4166
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not too bad 😉 Just kidding, thanks for the contribution. Got a nitpick there with the docs; and I'm wondering how attached you are to the default argument. And what others think.
Thanks for the review 😊 I'm not sure what implementations of object.get/object.dig would look like without the default argument. Would a missing key result in an error or instead return false to stop the evaluation of the rule? I feel like if it errors when there are missing keys, then it makes the builtins less useful for use cases involving arbitrary data. If it returns false, I feel it might be ambiguous? e.g.
|
Yeah So yeah, it makes sense to have both |
True, with that comparison it does make sense to have object.get with a default. I did wonder if object.dig could be object.get with an array param, but since array keys are valid Rego I figured it'd be clearer to add as a new function with an otherwise similar interface. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great addition! Thank you very much @charlieegan3 👍
The function name feels a little alien to me.. likely since I've never worked with Ruby. Could something like object.select
be considered?
Hey. Not at all wedded to the name, very open to alternative names including select. I had a little look here https://dev.to/obahareth/are-there-functions-similar-to-ruby-s-dig-in-other-languages-4c08 but other than get_in in elixer most languages seem to have this functionality with some form of optional/? style dot notation sugar. |
Yeah, Clojure uses get-in as well. I kinda like that as it also connects nicely to the already existing |
Thinking about this some more, couldn't |
Interesting, I did think about that but initially decided against it. If anyone is using object.get with an array key this would be hard to support without a breaking change. For example:
However, this is likely a rare use case so perhaps worth reconsidering? |
Oh, right—I keep forgetting that's even an option. Yeah, I guess we'll need to go with |
On second thought - that type of key will never exist in |
That's fair enough, it's certainly not valid JSON to find in the input document. I can change this to alter the functionality of Thanks for the feedback on this, much appreciated 😊 I'll pick this up in early January 🎄 |
Awesome @charlieegan3 👍 |
I've booked a day to work on this again on Monday 🙂 |
In f4beb29 I have updated the implementation of object.get to have a similar functionality to object.dig when passed an array 'key'. I have however realised that this will need some WASM changes too (comment). I'm going to look into this now - I might be able to use a Cloud VM to get this working while WASM is still a bit tricky on Apple M1. |
In 964c24a I have attempted to implement the same functionality in C for WASM support. I think that this part is not working as expected - I haven't had the time yet to work out why. I'll try and make some time later in the week to look into it again but any pointers much appreciated 🙂 opa_object_elem_t *elem = opa_object_get(opa_cast_object(obj), k);
if (elem == NULL)
{
return value;
} |
Here's a trick, I don't know if you've been aware: We can do printf-style debugging in wasm! When you put opa_println(opa_json_dump(elem)); in the code, and use |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good to me! I've left two minor comments on the topdown implementation.
Thanks for this feedback (and the helpful WASM debugging pointers too!). I had hoped to have time for this on Wednesday but didn't. I'll try and take another look on Sunday or Monday and try and get this working finally! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@charlieegan3 thanks for adjusting the PR! Two small nits. Assuming @srenatus is good w/ the Wasm changes, then LGTM.
re: using ast.Ref inside of wasm--correct, this only applies to the Go implementation.
Thanks @tsandall for the clarification regarding ast.Ref 👍
@srenatus thanks for this, helped a lot with the c implementation! Let me know what you think, & think regarding #4166 (comment) / _validate_json_path |
Sorry for the radio silence, I'll have a look in a few minutes. Generally, if what we have now (I've skimmed it) works fine, then let's go with that; but I'm curious what was happening there regardless. |
Hmm so, having checked out 9a50f7bee7b6737ea99c98deda51ea787451ffb9, and running
But I've noticed this in the build output:
and that would be bad form of course. What you've got here is fine, let's roll with that. |
Thanks Stephan.
I too noticed this but thought I might have just been missing a header import or something? Interesting you didn't get the same panic. I was having a think yesterday and think given this change, it makes sense to have a test case for the nested array paths. e.g. d03b299 However, this will now fail but only for the wasm SDK:
I think it makes sense to have the functionality the same here, I'll try and have a got at this later today or tomorrow. |
Yeah that would be preferable. Thank you! |
Hi again @srenatus, I've had another go and seem to passing the automated checks ✅. I think it matches the object.Find semantics (now used in the go implementation) as best I can. I've marked this as ready for review again, hope that's ok. Thanks too @anderseknert for the link in https://openpolicyagent.slack.com/archives/CBR63TK2A/p1643093622163300?thread_ts=1643076899.155000&cid=CBR63TK2A, great to see that this is something that others might find useful too 😊 |
Of course! This feature has been requested every now and then for at least a few years, so you're definitely solving a real problem here, and I'm looking forward to having this in OPA! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thanks a lot. Would you mind squashing the commits, adding a short message to the remaining one, so we can get this merged? 🚀
This commit extends the go and wasm implementations of object.get to allow a key to also be an array. When passed an array, each element in the array will be used as a key in turn. This allows values at deeply nested paths to be extracted from objects. It also supports getting indexes of nested arrays. The functionality was originally inspired by Ruby's Hash.dig function: https://ruby-doc.org/core-2.3.0_preview1/Hash.html#method-i-dig however we opted to include the behavior in object.get instead after being uncertain 'dig' was a commonly understood name. Signed-off-by: Charlie Egan <charlieegan3@users.noreply.github.com>
Thanks guys! |
Thank you Charlie! This is a great addition to OPA 🚀 |
This PR will change the behavior of object.get to, when passed an array as the key value, interpret that as a path, and perform a series of object.get operations on a the object and objects nested within it along that path.
Original Body:
This adds a new builtin
object.dig
to allow the extracting of data from nested objects. This is to make it easier for users of the Rego language to extract data from deeply nested input objects.The name and functionality were inspired by Ruby's Hash.dig function.