-
-
Notifications
You must be signed in to change notification settings - Fork 190
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
Add coll.JQ using gojq library #1585
Conversation
@hairyhenderson, I'd like to allow variables defined in the template to be used within JQ expressions. gojq provides a way to do that using This is how I'd use it (using hard-coded variables + values as an example): func JQ(jqExpr string, in interface{}) (interface{}, error) {
query, err := gojq.Parse(jqExpr)
variables := []string{"$testVariable1", "$testVariable2"} // TODO: Use variable names from context
code, err := gojq.Compile(query, gojq.WithVariables(variables))
iter := code.Run(in, "test value 1", "test value 2") // TODO: Use variable values from context
... Is there a way to do what I want? |
Co-authored-by: Dave Henderson <[email protected]>
Co-authored-by: Dave Henderson <[email protected]>
Co-authored-by: Dave Henderson <[email protected]>
Co-authored-by: Dave Henderson <[email protected]>
Co-authored-by: Dave Henderson <[email protected]>
Thanks for this, @ahochsteger - as to your questions:
I'm not sure if this is going to be straightforward. Template functions don't have access to the template's context other than through passing in arguments. To allow this would probably open up security risks in the general case. Perhaps an approach similar to the
In that case a variable However, it also may be a good idea to simply defer this and not support variable binding to begin with. It can be added later if there's demand.
I don't know that I see a reason to not allow this, especially as it's certainly possible to have an explicit JSON value of $ echo '[null]' | jq '.[0]'
null What's unfortunate about jq (and most JSON parsers) is there's effectively no difference between Either way, I think it's OK to return |
For this use case $ gojq -n '{"a":null} | has("a")'
true
$ gojq -n '{"a":null} | has("b")'
false |
coll/jq_test.go
Outdated
// TODO: Check if this is a valid test case (taken from jsonpath_test.go) since the struct | ||
// had to be converted to JSON and parsed from it again to be able to process using gojq. |
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.
🤔
I suppose this is because JQ can't be used with arbitrary structs or other types, which is perhaps something we should allow...
In the same vein, it might be useful to be able to pass the template context (gomplate.tmplctx
) as the input for something like:
$ gomplate -c books=https://openlibrary.org/subjects/fantasy.json -i '{{ jq `.works[].title` . }}'
Right now this fails with:
executing JQ failed: %!v(PANIC=Error method: invalid type: *gomplate.tmplctx (&map[books:map[key:/subjects/fantasy...
What's interesting in that particular case is that gomplate.tmplctx
is a map[string]interface{}
, which is in theory OK.
I'm going to hack on this a bit and make a commit if I can figure It out...
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.
Ok, I've gotten this to work:
$ bin/gomplate -c books=https://openlibrary.org/subjects/fantasy.json \
-i '{{ range jq `.books.works[].title` . -}}
title: {{.}}
{{end}}'
title: Alice's Adventures in Wonderland
title: Gulliver's Travels
title: Treasure Island
title: Through the Looking-Glass
title: A Midsummer Night's Dream
title: Il principe
title: The Wonderful Wizard of Oz
title: Avventure di Pinocchio
title: Alice's Adventures in Wonderland / Through the Looking Glass
title: Five Children and It
title: The Hobbit
title: Harry Potter and the Philosopher's Stone
Note that I've referenced the books
datasource in the .
context passed through as an argument.
Signed-off-by: Dave Henderson <[email protected]>
…erface{} Signed-off-by: Dave Henderson <[email protected]>
Signed-off-by: Dave Henderson <[email protected]>
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.
Thanks again for working on this, @ahochsteger!
I've added an integration test, and once the CI passes, this'll merge. |
Thanks for merging it, @hairyhenderson! |
@ahochsteger it'll be in 4.0.0 - too much has changed in I have no target date for 4.0, but in the meantime you can build your own binary from |
* feat: add coll.JQ using gojq library * fix: jq function naming (gojq -> jq) * test: add tests (take from jsonpath_test.go) * chore: add TODO for nil values (are they allowed?) * refactor: use fmt.Errorf instead of errors.Wrapf Co-authored-by: Dave Henderson <[email protected]> * fix: wrong alias for coll.JQ Co-authored-by: Dave Henderson <[email protected]> * docs: add links to JQ Co-authored-by: Dave Henderson <[email protected]> * test: add assertions after json marshal/unmarshal Co-authored-by: Dave Henderson <[email protected]> * refactor: use fmt.Errorf instead of errors.Wrapf Co-authored-by: Dave Henderson <[email protected]> * fix: test syntax and null handling * docs: improve documentation * docs: add blank line * Support cancellation Signed-off-by: Dave Henderson <[email protected]> * Support (almost) all types, not just map[string]interface{} and []interface{} Signed-off-by: Dave Henderson <[email protected]> * add an integration test for coll.JQ Signed-off-by: Dave Henderson <[email protected]> Signed-off-by: Dave Henderson <[email protected]> Co-authored-by: Andreas Hochsteger <[email protected]> Co-authored-by: Dave Henderson <[email protected]>
This PR adds support for the jq language to filter/transform complex data structures.
See [docs/content/functions/coll.md] for usage documentation.
Tasks:
coll.JQ
implementationQuestions:
coll.JQ
in this case) to returnnil
if the expression evaluates tonil
(or JSONnull
) or should an error be returned instead?-> Yes, should be ok. Should be mentioned in the documentation.
jsonpath
and currently done forjq
the same way. If an array returns just one element by accident it may break the template.-> Since there's no easy way to distinguish between an array with a single element and just a single element in the result it is kept the way it is done for
jsonpath
.Future enhancements:
Resolves #1584