Skip to content

Instantly share code, notes, and snippets.

@danbst
Last active March 7, 2020 21:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danbst/be08fde47e5645f568ff73133f8c0053 to your computer and use it in GitHub Desktop.
Save danbst/be08fde47e5645f568ff73133f8c0053 to your computer and use it in GitHub Desktop.
nixq - jq but with Nix syntax

nixq - jq but with Nix syntax

Familliar syntax and all of <nixpkgs/lib> and builtins in your hands.

Now going through jq tutorial:

Identity filter

$ # jq
$ curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | jq '.'
$ # nixq
$ curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' | nixq '_'

First element

$ # jq
$ ... | jq '.[0]'
$ # nixq, multiple versions
$ ... | nixq '_0'
$ ... | nixq 'elemAt _ 0'
$ ... | nixq 'head _'

Select several fields from first element, including some nested

$ # jq
$ jq '.[0] | {message: .commit.message, name: .commit.committer.name}'
$ # nixq
$ nixq 'with _0; { message = commit.message; name = commit.committer.name; }'

Same, but for all elements

$ # jq
$ jq '.[] | {message: .commit.message, name: .commit.committer.name}'
$ # nixq, unfortunately, can't do that in same fashion. But see next example

Same, but wrap result into a list, so it will be a valid JSON

$ # jq
$ jq '[.[] | {message: .commit.message, name: .commit.committer.name}]'
$ # nixq
$ nixq 'map (_: with _.commit; { message = message; name = committer.name; }) _'

Now the most complex expression from tutorial, don't know how to describe it in short

$ # jq
$ jq '[.[] | {message: .commit.message, name: .commit.committer.name, parents: [.parents[].html_url]}]'
$ # nixq
$ nixq 'map (_: { 
    message = _.commit.message;
    name = _.commit.committer.name;
    parents = map (_: _.html_url) _.parents;
  }) _'
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p jq nixUnstable
input=$(</dev/stdin)
prelude="
with import <nixpkgs/lib>;
with builtins;
let
_ = fromJSON ''$input'';
_0 = head _;
_1 = head _0;
_2 = head _1;
in $@
"
nix eval --json "($prelude)" | jq ".[0]"
@charles-dyfis-net
Copy link

charles-dyfis-net commented Nov 19, 2018

in $@ doesn't make much sense inside a string-assignment context in shell. It effectively gets coerced to $*, but makes the reader scratch their heads trying to figure out if it's in a context where it could be expanded into multiple words first. :)

...to be a little more clear about what I mean by multiple words...

set -- "first word" "second word" "third word"
printf '%s\n' "START$@END"

runs the command:

printf '%s\n' 'STARTfirst word' 'second word' 'third wordEND'

...retaining the original element separators. In assigning a value to a single string, you can't have separators at all.


I'd strongly suggest requiring a query to be passed as exactly one string, and making any other usage an explicit error. That way there's no magic going on behind the user's back in terms of how their arguments are or aren't reassembled (which is often particularly surprising if a user is trying to run a query involving quotes, which $@ or $* will discard when used as here).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment