mirror of
https://github.com/owenthereal/jqplay.git
synced 2025-04-19 06:02:17 +03:00
Don't require JSON input when null input is enabled (#174)
* Dont' require JSON input when null input is enabled Fixes #76 and also based a but on #85 by @zstadler * Add `docker compose watch` for easier development * Trigger run when query & `--null-input` are both not empty * Add test test to validate `--null-input` * Rename error with `Err` prefix --------- Co-authored-by: Owen Ou <o@owenou.com>
This commit is contained in:
parent
212a0e29f2
commit
1c739c7ff0
6
Makefile
6
Makefile
@ -37,4 +37,8 @@ setup:
|
||||
|
||||
.PHONY: start
|
||||
start:
|
||||
docker-compose up --build --force-recreate
|
||||
docker compose up --build --force-recreate
|
||||
|
||||
.PHONY: watch
|
||||
watch:
|
||||
docker compose watch
|
||||
|
@ -58,7 +58,7 @@ angular.module('jqplay.controllers', []).controller('JqplayCtrl', function Jqpla
|
||||
};
|
||||
|
||||
$scope.delayedRun = function (jq) {
|
||||
if ($scope.input.$valid) {
|
||||
if ($scope.input.$valid || (jq.q && jq.o.filter(f => f.name === "null-input" && f.enabled).length > 0)) {
|
||||
if ($scope.runTimeout != null) {
|
||||
$timeout.cancel($scope.runTimeout);
|
||||
$scope.runTimeout = null;
|
||||
|
@ -10,6 +10,15 @@ services:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
DATABASE_URL: "postgres://jqplay-user:jqplay-pass@db/jqplay-db?sslmode=disable"
|
||||
develop:
|
||||
watch: &watch
|
||||
- action: rebuild
|
||||
path: .
|
||||
ignore:
|
||||
- .git
|
||||
- .github
|
||||
- build
|
||||
- node_modules
|
||||
db:
|
||||
image: postgres:latest
|
||||
restart: always
|
||||
|
37
jq/jq.go
37
jq/jq.go
@ -19,15 +19,15 @@ func (e *ValidationError) Error() string {
|
||||
}
|
||||
|
||||
var (
|
||||
ExecTimeoutError = errors.New("jq execution was timeout")
|
||||
ExecCancelledError = errors.New("jq execution was cancelled")
|
||||
allowedOpts = map[string]struct{}{
|
||||
"slurp": struct{}{},
|
||||
"null-input": struct{}{},
|
||||
"compact-output": struct{}{},
|
||||
"raw-input": struct{}{},
|
||||
"raw-output": struct{}{},
|
||||
"sort-keys": struct{}{},
|
||||
ErrExecTimeout = errors.New("jq execution was timeout")
|
||||
ErrExecCancelled = errors.New("jq execution was cancelled")
|
||||
allowedOpts = map[string]struct{}{
|
||||
"slurp": {},
|
||||
"null-input": {},
|
||||
"compact-output": {},
|
||||
"raw-input": {},
|
||||
"raw-output": {},
|
||||
"sort-keys": {},
|
||||
}
|
||||
)
|
||||
|
||||
@ -37,11 +37,24 @@ type JQ struct {
|
||||
O []JQOpt `json:"o"`
|
||||
}
|
||||
|
||||
func (j *JQ) optIsEnabled(name string) bool {
|
||||
for _, o := range j.O {
|
||||
if o.Name == name {
|
||||
return o.Enabled
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type JQOpt struct {
|
||||
Name string `json:"name"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
func (o *JQOpt) String() string {
|
||||
return fmt.Sprintf("%s (%t)", o.Name, o.Enabled)
|
||||
}
|
||||
|
||||
func (j *JQ) Opts() []string {
|
||||
opts := []string{}
|
||||
for _, opt := range j.O {
|
||||
@ -70,10 +83,10 @@ func (j *JQ) Eval(ctx context.Context, w io.Writer) error {
|
||||
if err != nil {
|
||||
ctxErr := ctx.Err()
|
||||
if ctxErr == context.DeadlineExceeded {
|
||||
return ExecTimeoutError
|
||||
return ErrExecTimeout
|
||||
}
|
||||
if ctxErr == context.Canceled {
|
||||
return ExecCancelledError
|
||||
return ErrExecCancelled
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,7 +100,7 @@ func (j *JQ) Validate() error {
|
||||
errMsgs = append(errMsgs, "missing filter")
|
||||
}
|
||||
|
||||
if j.J == "" {
|
||||
if j.J == "" && !j.optIsEnabled("null-input") {
|
||||
errMsgs = append(errMsgs, "missing JSON")
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package jq
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
@ -28,6 +29,69 @@ func TestJQEvalInvalidInput(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestJQNullInputOption(t *testing.T) {
|
||||
cases := []struct {
|
||||
J string
|
||||
Q string
|
||||
O []JQOpt
|
||||
ErrStr string
|
||||
}{
|
||||
{
|
||||
Q: ".",
|
||||
O: []JQOpt{
|
||||
{
|
||||
Name: "null-input",
|
||||
Enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
O: []JQOpt{
|
||||
{
|
||||
Name: "null-input",
|
||||
Enabled: true,
|
||||
},
|
||||
},
|
||||
ErrStr: "missing filter",
|
||||
},
|
||||
{
|
||||
J: `{"foo": "bar"}`,
|
||||
O: []JQOpt{
|
||||
{
|
||||
Name: "null-input",
|
||||
Enabled: true,
|
||||
},
|
||||
},
|
||||
ErrStr: "missing filter",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
c := c
|
||||
t.Run(fmt.Sprintf("j=%q q=%q o=%v", c.J, c.Q, c.O), func(t *testing.T) {
|
||||
jq := &JQ{
|
||||
J: c.J,
|
||||
Q: c.Q,
|
||||
O: c.O,
|
||||
}
|
||||
err := jq.Validate()
|
||||
if err == nil && c.ErrStr != "" {
|
||||
t.Errorf("err should not be nil: %s", c.ErrStr)
|
||||
}
|
||||
|
||||
if err != nil && c.ErrStr == "" {
|
||||
t.Errorf("err should be nil: %s", err)
|
||||
}
|
||||
|
||||
if err != nil && c.ErrStr != "" {
|
||||
if want, got := c.ErrStr, err.Error(); !strings.Contains(got, want) {
|
||||
t.Errorf(`err not equal: want=%v got=%v`, want, got)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJQValidateDisallowOpts(t *testing.T) {
|
||||
jq := &JQ{
|
||||
J: "{}",
|
||||
@ -56,7 +120,7 @@ func TestJQEvalTimeout(t *testing.T) {
|
||||
err := jq.Eval(ctx, io.Discard)
|
||||
cancel()
|
||||
|
||||
if err != ExecTimeoutError {
|
||||
if err != ErrExecTimeout {
|
||||
t.Errorf("err message should be jq execution timeout, but it's %s", err)
|
||||
}
|
||||
}
|
||||
@ -75,7 +139,7 @@ func TestJQEvalCancelled(t *testing.T) {
|
||||
}()
|
||||
err := jq.Eval(ctx, io.Discard)
|
||||
|
||||
if err != ExecCancelledError {
|
||||
if err != ErrExecCancelled {
|
||||
t.Errorf("err message should be jq execution timeout, but it's %s", err)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user