Skip to content

Commit

Permalink
rename to lqn
Browse files Browse the repository at this point in the history
  • Loading branch information
inconvergent committed Dec 30, 2023
1 parent 2c25e6c commit e08a81b
Show file tree
Hide file tree
Showing 21 changed files with 392 additions and 383 deletions.
10 changes: 5 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ RUN apt-get -qq remove curl -y &&\
from base AS build

WORKDIR /opt
ADD src quicklisp/local-projects/jqn/src
ADD test quicklisp/local-projects/jqn/test
ADD jqn.asd quicklisp/local-projects/jqn
ADD run-tests.sh quicklisp/local-projects/jqn/run-tests.sh
ADD src quicklisp/local-projects/lqn/src
ADD test quicklisp/local-projects/lqn/test
ADD lqn.asd quicklisp/local-projects/lqn
ADD run-tests.sh quicklisp/local-projects/lqn/run-tests.sh
RUN mkdir -p ~/quicklisp/ && ln -s /opt/quicklisp/setup.lisp ~/quicklisp/setup.lisp

WORKDIR /opt/quicklisp/local-projects/jqn/
WORKDIR /opt/quicklisp/local-projects/lqn/

CMD ["bash", "./run-tests.sh"]
23 changes: 12 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# JQN - JSON Query Notation
# LQN - Lisp Query Notation

JQN is a terminal utility (and Common Lisp library) to query and transform
JSON. It consists of two terminal commands `jqn` and `tqn`.
LQN is a terminal utility (and Common Lisp library) to query and transform
Lisp data, JSON and TXT files. It consists of three terminal commands `lqn`,
`jqn` and `tqn`.

## JQN Example (JSON)

Expand Down Expand Up @@ -34,7 +35,7 @@ which returns (something like):
## TQN Example (TXT)

`tqn` is a mode for reading lines of text into a `vector` (JSON array). `tqn`
has slightly different default behaviour to `jqn`. Notably that it ignores
has slightly different default behaviour to `jqn`. Notably, it ignores
`nil` in the output. `tqn` defaults to printing the vector as rows, but `-j`
will output to JSON instead. `-t` does the oposite for `jqn`.

Expand Down Expand Up @@ -154,11 +155,11 @@ only argument.

## Query Utility Functions

The internal representation of JSON data as `vectors` and `kvs` in `jqn` means
The internal representation of JSON data as `vectors` and `kvs` in `lqn` means
you can use the regular CL utilities such as `gethash`, `aref`, `subseq`,
`length` etc.

But for convenience there are a few special functions defined in `jqn`.
But for convenience there are a few special functions defined in `lqn`.

### Global Context
- `(ctx)`: returns `:pipe` if input is from `stdin`; otherwise `:file`.
Expand Down Expand Up @@ -232,13 +233,13 @@ Command line options:

## Install

Make sure `jqn` is available in your `quicklisp` `local-projects` folder Then
Make sure `lqn` is available in your `quicklisp` `local-projects` folder Then
create an alias for SBCL to execute shell wrappers e.g:
```
alias jqn="sbcl --script ~/path/to/jqn/bin/jqn-sh.lisp"
alias tqn="sbcl --script ~/path/to/jqn/bin/tqn-sh.lisp"
alias jqn="sbcl --script ~/path/to/lqn/bin/jqn-sh.lisp"
alias tqn="sbcl --script ~/path/to/lqn/bin/tqn-sh.lisp"
alias lqn="sbcl --script ~/path/to/lqn/bin/lqn-sh.lisp"
```
Unfortunately this will tend to be quite slow. To get around this you can
create an image that has `jqn` preloaded and dump it using
create an image that has `lqn` preloaded and dump it using
`sb-ext:save-lisp-and-die`. Then use your image in the alias instead of SBCL.

18 changes: 9 additions & 9 deletions bin/ex.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@
(load "~/quicklisp/setup.lisp")

; (ql:quickload :auxin :silent t)
(ql:quickload :jqn :silent t)
(ql:quickload :lqn :silent t)

(defmacro pretty-json (v) `(jqn:out (jqn::jsnout* ,v :indent t)))
(defmacro pretty-json (v) `(lqn:out (lqn:jsnstr ,v :indent t)))

(defun main ()

(pretty-json
(jqn:jsnqryf (jqn::internal-path-string "data/sample.json")
(lqn:jsnqryf (lqn::internal-path-string "data/sample.json")
(|| #{_id (things #[name])})))

(print (jqn:qry "1 x 1 x 7 x 100" (splt _ :x) int!? (*fld 0 (+ _))))
(print (jqn:qry "1 x 1 x 7 x 100" (splt _ :x) int!? (*fld 0 +)))
(print (jqn:qry "1 x 1 x 7 x 100" (splt _ :x) int!? (*fld 0 acc (- _ acc))))
(print (lqn:qry "1 x 1 x 7 x 100" (splt _ :x) int!? (*fld 0 (+ _))))
(print (lqn:qry "1 x 1 x 7 x 100" (splt _ :x) int!? (*fld 0 +)))
(print (lqn:qry "1 x 1 x 7 x 100" (splt _ :x) int!? (*fld 0 acc (- _ acc))))

(pretty-json
(jqn:qry "1 x 1 x 7 x 100"
(lqn:qry "1 x 1 x 7 x 100"
(splt _ :x) int!? ; split and parse as int
($new :num (num) ; new nested dict
:items (*map ($new :v _ :i (cnt))))))
Expand All @@ -27,7 +27,7 @@
; { "v": 7, "i": 2 }, { "v": 100, "i": 3 } ] }

(pretty-json
(jqn:qry #("1 x 1 x 7 x 100" "3 x 8 x 30")
(lqn:qry #("1 x 1 x 7 x 100" "3 x 8 x 30")
(*map (splt _ :x) int!? ; for each row, split and parse as int
($new :num (num) ; new nested dict for each row
:items (*map ($new :v _ :i (cnt)))))))
Expand All @@ -39,7 +39,7 @@
; { "v": 30, "i": 2 } ] } ]

(pretty-json
(jqn:qry "1 x 1 x 7 x 100 $ 3 x 8 x 30"
(lqn:qry "1 x 1 x 7 x 100 $ 3 x 8 x 30"
(splt _ :$)
(*map (splt _ :x) int!? ; for each row, split and parse as int
($new :num (num) ; new nested dict for each row
Expand Down
15 changes: 7 additions & 8 deletions bin/jqn-sh.lisp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(ql:quickload :jqn :silent t)
(in-package :jqn)
(ql:quickload :lqn :silent t)
(in-package :lqn)

(defvar *jqnex* "
(defvar *ex* "
QUERY AND TRANSFORM JSON
Usage:
Expand All @@ -25,7 +25,6 @@ Examples:
echo '{\"_id\": 1}' | jqn '{_id}' # query data from pipe
")

; TODO: warn if jqn reads only some of a file?
(defun jqn/execute-query (opts dat q &key conf db)
(handler-case (qryl dat q :conf conf :db db)
(error (e) (exit-with-msg 4 "jqn: failed to execute qry:~%~a" e))))
Expand All @@ -39,8 +38,8 @@ Examples:
(error (e) (exit-with-msg 3 "jqn: failed to parse qry:~%~a" (mkstr e)))))

(defun jqn/run-files (opts q files)
(unless q (exit-with-msg 1 "jqn: missing query.~%~a~&" *jqnex*))
(unless (< 0 (length files)) (exit-with-msg 2 "jqn: missing files.~%~a~&" *jqnex*))
(unless q (exit-with-msg 1 "jqn: missing query.~%~a~&" *ex*))
(unless (< 0 (length files)) (exit-with-msg 2 "jqn: missing files.~%~a~&" *ex*))
(loop for f in files for i from 0
do (sh/out :json opts
(jqn/execute-query opts (jqn/loadf-with-err f) (jqn/parse-query q)
Expand All @@ -49,15 +48,15 @@ Examples:
:db (verbose? opts)))))

(defun jqn/run-pipe (opts q)
(unless q (exit-with-msg 1 "jqn: missing query.~%~a~&" *jqnex*))
(unless q (exit-with-msg 1 "jqn: missing query.~%~a~&" *ex*))
(sh/out :json opts
(jqn/execute-query opts (jsnloads *standard-input*) (jqn/parse-query q)
:conf `((:mode . :jqn) (:ctx . :pipe))
:db (verbose? opts))))

(defun jqn/run-from-shell (args)
(multiple-value-bind (opts args) (split-opts-args args)
(when (help? opts) (exit-with-msg 0 *jqnex*))
(when (help? opts) (exit-with-msg 0 *ex*))
(cond ((interactive-stream-p *standard-input*)
(jqn/run-files opts (car args) (cdr args)))
(t (jqn/run-pipe opts (car args))))))
Expand Down
42 changes: 21 additions & 21 deletions bin/lqn-sh.lisp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
(ql:quickload :jqn :silent t)
(in-package :jqn)
(ql:quickload :lqn :silent t)
(in-package :lqn)

(defvar *ex* "
QUERY AND TRANSFORM TXT
Usage:
jqn [options] <qry> [files ...]
cat sample.csv | jqn [options] <qry>
lqn [options] <qry> [files ...]
cat sample.csv | lqn [options] <qry>
Options:
-v prints the full compiled qry to stdout before the result
Expand All @@ -22,44 +22,44 @@ Examples:
")

(defun jqn/execute-query (opts dat q &key conf db)
(defun lqn/execute-query (opts dat q &key conf db)
(handler-case (qryl dat q :conf conf :db db)
(error (e) (exit-with-msg 4 "jqn: failed to execute qry:~%~a" e))))
(error (e) (exit-with-msg 4 "lqn: failed to execute qry:~%~a" e))))

(defun jqn/load-with-err (f)
(defun lqn/load-with-err (f)
(handler-case (read-file-as-data-vector f)
(error (e) (exit-with-msg 2 "jqn: failed to read txt file: ~a~%~a" f e))))
(error (e) (exit-with-msg 2 "lqn: failed to read txt file: ~a~%~a" f e))))

(defun jqn/parse-query (args)
(defun lqn/parse-query (args)
(handler-case `(|| ,@(read-all-str args))
(error (e) (exit-with-msg 3 "jqn: failed to parse qry:~%~a" (mkstr e)))))
(error (e) (exit-with-msg 3 "lqn: failed to parse qry:~%~a" (mkstr e)))))

(defun jqn/run-files (opts q files)
(defun lqn/run-files (opts q files)
(when (help? opts) (exit-with-msg 0 *ex*))
(unless q (exit-with-msg 1 "jqn: missing query.~%~a~&" *ex*))
(unless (< 0 (length files)) (exit-with-msg 2 "jqn: missing files.~%~a~&" *ex*))
(unless q (exit-with-msg 1 "lqn: missing query.~%~a~&" *ex*))
(unless (< 0 (length files)) (exit-with-msg 2 "lqn: missing files.~%~a~&" *ex*))
(loop for f in files for i from 0
do (sh/out :ldn opts
(jqn/execute-query opts (jqn/load-with-err f) (jqn/parse-query q)
(lqn/execute-query opts (lqn/load-with-err f) (lqn/parse-query q)
:conf `((:mode . :lqn) (:fn . ,f)
(:fi . ,i) (:ctx . :file))
:db (verbose? opts)))))

; (defun jqn/run-pipe (opts q)
; (defun lqn/run-pipe (opts q)
; (when (help? opts) (exit-with-msg 0 *ex*))
; (unless q (exit-with-msg 1 "jqn: missing query.~%~a~&" *ex*))
; (unless q (exit-with-msg 1 "lqn: missing query.~%~a~&" *ex*))
; (labels ((one-line (v) (if (> (length v) 1) v (aref v 0))))
; (sh/out :txt opts
; (jqn/execute-query opts (one-line (read-stream-lines-as-vector)) (jqn/parse-query q)
; (lqn/execute-query opts (one-line (read-stream-lines-as-vector)) (lqn/parse-query q)
; :conf `((:mode . :lqn) (:ctx . :pipe))
; :db (verbose? opts)))))

(defun jqn/run-from-shell (args)
(defun lqn/run-from-shell (args)
(multiple-value-bind (opts args) (split-opts-args args)
(cond ((interactive-stream-p *standard-input*)
(jqn/run-files opts (car args) (cdr args)))
(t (error "bad") (jqn/run-pipe opts (car args)))
(lqn/run-files opts (car args) (cdr args)))
(t (error "bad") (lqn/run-pipe opts (car args)))
)))

(jqn/run-from-shell (cdr (cmd-args)))
(lqn/run-from-shell (cdr (cmd-args)))

16 changes: 8 additions & 8 deletions bin/tqn-sh.lisp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(ql:quickload :jqn :silent t)
(in-package :jqn)
(ql:quickload :lqn :silent t)
(in-package :lqn)

(defvar *tqnex* "
(defvar *ex* "
QUERY AND TRANSFORM TXT
Usage:
Expand Down Expand Up @@ -42,9 +42,9 @@ Examples:
(error (e) (exit-with-msg 3 "tqn: failed to parse qry:~%~a" (mkstr e)))))

(defun tqn/run-files (opts q files)
(when (help? opts) (exit-with-msg 0 *tqnex*))
(unless q (exit-with-msg 1 "tqn: missing query.~%~a~&" *tqnex*))
(unless (< 0 (length files)) (exit-with-msg 2 "tqn: missing files.~%~a~&" *tqnex*))
(when (help? opts) (exit-with-msg 0 *ex*))
(unless q (exit-with-msg 1 "tqn: missing query.~%~a~&" *ex*))
(unless (< 0 (length files)) (exit-with-msg 2 "tqn: missing files.~%~a~&" *ex*))
(loop for f in files for i from 0
do (sh/out :txt opts
(tqn/execute-query opts (tqn/load-with-err f) (tqn/parse-query q)
Expand All @@ -53,8 +53,8 @@ Examples:
:db (verbose? opts)))))

(defun tqn/run-pipe (opts q)
(when (help? opts) (exit-with-msg 0 *tqnex*))
(unless q (exit-with-msg 1 "tqn: missing query.~%~a~&" *tqnex*))
(when (help? opts) (exit-with-msg 0 *ex*))
(unless q (exit-with-msg 1 "tqn: missing query.~%~a~&" *ex*))
(labels ((one-line (v) (if (> (length v) 1) v (aref v 0))))
(sh/out :txt opts
(tqn/execute-query opts (one-line (read-stream-lines-as-vector)) (tqn/parse-query q)
Expand Down
6 changes: 3 additions & 3 deletions compile.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/bin/bash

set -e
touch ./jqn.asd
touch ./lqn.asd
time sbcl --quit \
--eval '(load "jqn.asd")'\
--eval '(handler-case (time (ql:quickload :jqn :verbose t))
--eval '(load "lqn.asd")'\
--eval '(handler-case (time (ql:quickload :lqn :verbose t))
(error (c) (print c) (sb-ext:quit :unix-status 2)))'\
>compile.sh.tmp 2>&1
Loading

0 comments on commit e08a81b

Please sign in to comment.