-
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
Proposal: object.update
builtin function
#2839
Comments
Sorry for the delayed reply. This seems totally reasonable. We had an issue a while ago that proposed a
As far as naming goes, what about
I'd expect the path segment and value would have to be the same. E.g.,
I'd let the use cases dictate the behaviour for now. We could always add the other variant in the future. If we allow overlapped updates to apply, I'd lean toward ensuring a stable order (e.g., by sorting by path and value.) |
I read through the earlier discussion in those tickets. Full JSON-patch seems |
This is an implementation of the `json.patch` builtin. Previous discussions about this include open-policy-agent#2839 and open-policy-agent#2167. It does not use an external dependency but rather implements [RFC 6902] directly on AST terms. This avoids a conversion to JSON as well as the dependency; and as an added bonus we can make `json.patch` work for sets as well, covering the full space of AST terms. In my first implementation I used a mutable approach by first creating a deep copy and then modifying it in-place. However, this leads to issues with the cached `hash` values in objects on the path. I replaced this with an implementation that creates shallow copies. The performance tradeoff is that smaller patches should be faster; but replacing parts will be slower. Since we don't know about too many people using this, I think both sides are acceptable. I vendored the [json-patch-tests] into the test suite in a way that should make updating them fairly easy. I am also testing the cases disabled there (since they do work for us!) but I disabled two test cases by adding a new `opa_disabled` key. These are: - Us allowing `"foo"` as path (which should be `"/foo"` if you interpret the RFC strictly). - A duplicate entry in the JSON patch object which isn't caught by OPA since it's consistent. I added some additional tests for sets and things seem to work. I'm going to try out this new functionality in our larger codebase to see if any issues come up, but I expect it to hold up. Update: we've been using this builtin and haven't seen any issues so far. [RFC 6902]: https://tools.ietf.org/html/rfc6902#section-4.4 [json-patch-tests]: https://github.com/json-patch/json-patch-tests Signed-off-by: Jasper Van der Jeugt <jasper@fugue.co>
This is an implementation of the `json.patch` builtin. Previous discussions about this include #2839 and #2167. It does not use an external dependency but rather implements [RFC 6902] directly on AST terms. This avoids a conversion to JSON as well as the dependency; and as an added bonus we can make `json.patch` work for sets as well, covering the full space of AST terms. In my first implementation I used a mutable approach by first creating a deep copy and then modifying it in-place. However, this leads to issues with the cached `hash` values in objects on the path. I replaced this with an implementation that creates shallow copies. The performance tradeoff is that smaller patches should be faster; but replacing parts will be slower. Since we don't know about too many people using this, I think both sides are acceptable. I vendored the [json-patch-tests] into the test suite in a way that should make updating them fairly easy. I am also testing the cases disabled there (since they do work for us!) but I disabled two test cases by adding a new `opa_disabled` key. These are: - Us allowing `"foo"` as path (which should be `"/foo"` if you interpret the RFC strictly). - A duplicate entry in the JSON patch object which isn't caught by OPA since it's consistent. I added some additional tests for sets and things seem to work. I'm going to try out this new functionality in our larger codebase to see if any issues come up, but I expect it to hold up. Update: we've been using this builtin and haven't seen any issues so far. [RFC 6902]: https://tools.ietf.org/html/rfc6902#section-4.4 [json-patch-tests]: https://github.com/json-patch/json-patch-tests Signed-off-by: Jasper Van der Jeugt <jasper@fugue.co>
Fixed by #2909 |
I'd like to propose a new builtin function to handle some limited cases of
recursion. We already allow recursively iterating over an object using
walk(obj)
. However, there's no way to use resulting outputs to update theoriginal object (or construct a new one).
This is because comprehensions only allow us to update or create objects with
known (fixed) depth. This proposal attempts to fix that using a new builtin
function
object.update
.I imagine it would look a lot like this:
Where
doc
is an object (or array), for example:And
patches
is a array of tuples. These tuples are exactly the same shapeas the output of
walk(obj)
: a path together with a value. For example,this could be the
patches
array:Applying these patches to the original
doc
would apply the updates to theobject:
In the concrete use case I encountered this it would also be extremely useful
to be able to insert new keys into the object. This would mean the following
holds as well:
If you combine
walk
andobject.update
, you can do relatively complex generictree traversals, such as incrementing all numbers in a tree:
It can also be used to merge two objects in more interesting ways than
object.merge
allows for. The concrete use case I'm interested in is mergingtogether different views on terraform resources.
Because this is what every normal sane person would I've actually given
implementing
update
a try in pure Rego and it seems to work well. Of coursereplacing this by a builtin would drastically improve performance and I wouldn't
have the recursion limit anymore.
This is of course still a draft and there's some open questions:
object.update
a good name?there.
just apply them in the order they are given?
The text was updated successfully, but these errors were encountered: