Skip to content

feat(builtins): implement json.filter, json.patch, json.remove - #193

Merged
philipaconrad merged 1 commit into
open-policy-agent:mainfrom
DFrenkel:builtins-objects
Aug 6, 2026
Merged

feat(builtins): implement json.filter, json.patch, json.remove#193
philipaconrad merged 1 commit into
open-policy-agent:mainfrom
DFrenkel:builtins-objects

Conversation

@DFrenkel

@DFrenkel DFrenkel commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

What code changed, and why?

Add the object-category JSON builtins (json.filter, json.patch, json.remove), matching OPA Go semantics. They address nested locations by JSON-Pointer path (RFC6901: a /-separated string with ~0/~1 unescaping, or an array of segments) rather than operating on JSON text.

  • filter/remove take a set or array of paths, collapse them into a single tree, and walk the input once to keep or drop the named locations; a shorter path subsumes a longer one ("a" covers "a/b"). patch applies RFC6902 operations (add/remove/replace/move/copy/test) over objects, arrays, sets, and scalars; a failed operation (bad path, failed test, unknown op) becomes undefined under non-strict evaluation.

  • patch is implemented directly on the immutable RegoValue tree rather than porting OPA's mutable edittree. edittree avoids re-copying the document as many edits are applied in place. Because RegoValue is an immutable value type (copy-on-write), the same RFC6902 behavior comes from plain recursive get/insert/remove functions that return new values. A patch applies its operations to one document and returns the result, so there's no repeated in-place editing for edittree to speed up, and copy-on-write keeps the intermediate copies cheap. It passes the full json-patch-tests conformance set this way.

Definition of done

All relevant json(filter|remove|patch) compliance tests pass except for existing known issues

How to test

make fmt lint test
OPA_COMPLIANCE_TESTS=".*json(filter|remove|patch).*" make test-compliance

Related Resources

Fixes #192

Add the path-based JSON builtins from the object category. They operate on
the decoded RegoValue tree rather than JSON text, using JSON-Pointer paths
(RFC6901).

- json.filter / json.remove parse the paths argument into one tree, then walk
  the input once to keep or drop the named locations (a shorter path subsumes
  a longer one).
- json.patch applies RFC6902 operations (add/remove/replace/move/copy/test)
  by folding recursive get/insert/remove helpers over the value. Operation
  failures throw, surfacing as undefined under non-strict evaluation.

Fixes open-policy-agent#192

Signed-off-by: Dmitry Frenkel <d_frenkel@apple.com>
@DFrenkel
DFrenkel requested a review from philipaconrad July 27, 2026 23:03

@philipaconrad philipaconrad left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a correct port of the json.filter, json.patch, and json.remove builtins.

I'm not sure that I agree with all of the rationale around why edittree-style structures would be less effective here, but I do agree that porting that sort of bookkeeping structure would have enormously complicated the PR.

If we get complaints around json.patch's performance in the future, we can investigate and see if alternative data structures like the edittree design would be worth trying out.

For now though, I think this is good to ship. Thanks @DFrenkel!

@philipaconrad
philipaconrad merged commit 633c562 into open-policy-agent:main Aug 6, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

builtins: implement path-based JSON object builtins (json.filter, json.patch, json.remove)

2 participants