diff --git a/.github/workflows/coverage_profile_uploading.yml b/.github/workflows/coverage_profile_uploading.yml
new file mode 100644
index 0000000..110da39
--- /dev/null
+++ b/.github/workflows/coverage_profile_uploading.yml
@@ -0,0 +1,43 @@
+name: Coverage profile uploading
+
+on:
+ workflow_run:
+ workflows:
+ - Test
+ branches:
+ - master
+ - develop
+ types:
+ - completed
+
+jobs:
+ upload:
+ runs-on: ubuntu-latest
+ if: ${{ github.event.workflow_run.conclusion == 'success' }}
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up Go
+ uses: actions/setup-go@v3
+ with:
+ go-version: 1.x
+
+ - name: Create Coverage Profile
+ run: go test -coverprofile=coverage.txt -covermode=atomic ./...
+
+ - name: Upload Coverage Profile
+ uses: codecov/codecov-action@v2
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ files: coverage.txt
+ fail_ci_if_error: true
+ verbose: true
+ fail:
+ runs-on: ubuntu-latest
+ if: ${{ github.event.workflow_run.conclusion == 'failure' }}
+
+ steps:
+ - run: |
+ echo '::error::Testing was failed'
+ exit 1
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..1ecca74
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,17 @@
+name: Test
+
+on: push
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up Go
+ uses: actions/setup-go@v3
+ with:
+ go-version: 1.x
+
+ - name: Test
+ run: go test ./... --cover
diff --git a/.github/workflows/test_on_the_previous_go_version.yml b/.github/workflows/test_on_the_previous_go_version.yml
new file mode 100644
index 0000000..b434369
--- /dev/null
+++ b/.github/workflows/test_on_the_previous_go_version.yml
@@ -0,0 +1,17 @@
+name: Test on the previous Go version
+
+on: push
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Set up Go
+ uses: actions/setup-go@v3
+ with:
+ go-version: 1.17.x
+
+ - name: Test
+ run: go test ./... --cover
diff --git a/README.md b/README.md
index cb6e679..8093c5d 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,9 @@
SQL-like query language for csv
-[](https://travis-ci.org/mithrandie/csvq)
+[](https://github.com/mithrandie/csvq/actions/workflows/test.yml)
[](https://codecov.io/gh/mithrandie/csvq)
+[](https://opensource.org/licenses/MIT)
csvq is a command line tool to operate CSV files.
You can read, update, delete CSV records with SQL-like query.
@@ -59,7 +60,7 @@ Go 1.17 or later (cf. [Getting Started - The Go Programming Language](https://go
#### Build command
-```$ env GO111MODULE=on go get github.com/mithrandie/csvq```
+```$ go install github.com/mithrandie/csvq```
### Install using package manager
diff --git a/docs/_posts/2006-01-02-command.md b/docs/_posts/2006-01-02-command.md
index 2f0ecf0..f8a35cf 100644
--- a/docs/_posts/2006-01-02-command.md
+++ b/docs/_posts/2006-01-02-command.md
@@ -178,7 +178,7 @@ Regardless of this option, files with the following extensions will be read in a
: Strip line break from the end of files and query results.
--format value, -f value
-: Format of query results. The default is _TEXT_.
+: Format of query results. The default is _TEXT_, but _CSV_ is used for output to pipe.
| value(case ignored) | format |
|:--------------------|:-------------------------------------------------------------------|
diff --git a/docs/_posts/2006-01-02-install.md b/docs/_posts/2006-01-02-install.md
index 56f4449..88d9b31 100644
--- a/docs/_posts/2006-01-02-install.md
+++ b/docs/_posts/2006-01-02-install.md
@@ -25,7 +25,7 @@ Go 1.17 or later (cf. [Getting Started - The Go Programming Language](https://go
### Build command
-```$ env GO111MODULE=on go get github.com/mithrandie/csvq```
+```$ go install github.com/mithrandie/csvq```
## Install using package manager
{: #install-using-package-manager}
diff --git a/docs/sitemap.xml b/docs/sitemap.xml
index 784cdfb..966e4ae 100644
--- a/docs/sitemap.xml
+++ b/docs/sitemap.xml
@@ -14,11 +14,11 @@
https://mithrandie.github.io/csvq/reference/install.html
- 2022-03-23T00:27:45+00:00
+ 2022-06-18T18:12:31+00:00
https://mithrandie.github.io/csvq/reference/command.html
- 2022-06-17T12:04:02+00:00
+ 2022-06-18T12:43:41+00:00
https://mithrandie.github.io/csvq/reference/statement.html
diff --git a/go.mod b/go.mod
index 0680b90..cdb226c 100644
--- a/go.mod
+++ b/go.mod
@@ -2,18 +2,16 @@ module github.com/mithrandie/csvq
require (
github.com/mitchellh/go-homedir v1.0.0
- github.com/mithrandie/go-file/v2 v2.0.2
+ github.com/mithrandie/go-file/v2 v2.1.0
github.com/mithrandie/go-text v1.5.3
- github.com/mithrandie/readline-csvq v1.1.1
+ github.com/mithrandie/readline-csvq v1.2.0
github.com/mithrandie/ternary v1.1.1
github.com/urfave/cli v1.20.0
- golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
- golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1
+ golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
+ golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c
+ golang.org/x/text v0.3.7
)
-require (
- golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
- golang.org/x/text v0.3.7 // indirect
-)
+require golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
go 1.17
diff --git a/go.sum b/go.sum
index dcb4813..b429346 100644
--- a/go.sum
+++ b/go.sum
@@ -1,23 +1,23 @@
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mithrandie/go-file/v2 v2.0.2 h1:3/yzItlTssDX9wOZrj9MtRyXbr52OZURmXFMuvpJ6Fg=
-github.com/mithrandie/go-file/v2 v2.0.2/go.mod h1:98a9loPjYr7ffsfwMDdJ7iH/dO8EXAca8XiI6SZpPV8=
+github.com/mithrandie/go-file/v2 v2.1.0 h1:XA5Tl+73GXMDvgwSE3Sg0uC5FkLr3hnXs8SpUas0hyg=
+github.com/mithrandie/go-file/v2 v2.1.0/go.mod h1:9YtTF3Xo59GqC1Pxw6KyGVcM/qubAMlxVsqI/u9r++c=
github.com/mithrandie/go-text v1.5.3 h1:A+/mtgUsr1EsoVKGb4sm8Suho/Biku9Sh2appII4Mo0=
github.com/mithrandie/go-text v1.5.3/go.mod h1:yaVYauF3TLf7LvjGrrQB/mffIkohXTXJpW9zQ206UL8=
-github.com/mithrandie/readline-csvq v1.1.1 h1:kp9W5WPUAB+NOgW5axPdu8mZe1M9CP/D1xpabj39JVY=
-github.com/mithrandie/readline-csvq v1.1.1/go.mod h1:eOJt0j6UI9lhwM/KP+v40ugarhXsnPIXStvkfIaq79E=
+github.com/mithrandie/readline-csvq v1.2.0 h1:5GFbdWFP+2m57Yz+XLtKVIfyH0SjN9du51VT0x9WI40=
+github.com/mithrandie/readline-csvq v1.2.0/go.mod h1:6Grnfrl8PHC448fV7f8RJNlHeoM+Z3w2QlYW+J9mA2I=
github.com/mithrandie/ternary v1.1.1 h1:k/joD6UGVYxHixYmSR8EGgDFNONBMqyD373xT4QRdC4=
github.com/mithrandie/ternary v1.1.1/go.mod h1:0D9Ba3+09K2TdSZO7/bFCC0GjSXetCvYuYq0u8FY/1g=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
-golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
-golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
+golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/sys v0.0.0-20191029155521-f43be2a4598c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU=
+golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
diff --git a/init_windows.go b/init_windows.go
index c0a6bc7..109d36c 100644
--- a/init_windows.go
+++ b/init_windows.go
@@ -1,4 +1,4 @@
-// +build windows
+//go:build windows
package main
diff --git a/lib/action/signals_default.go b/lib/action/signals_default.go
index 0a0bed7..95498eb 100644
--- a/lib/action/signals_default.go
+++ b/lib/action/signals_default.go
@@ -1,4 +1,4 @@
-// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
+//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows
package action
diff --git a/lib/action/signals_posix.go b/lib/action/signals_posix.go
index ac1ee63..ce23bac 100644
--- a/lib/action/signals_posix.go
+++ b/lib/action/signals_posix.go
@@ -1,4 +1,4 @@
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
package action
diff --git a/lib/cmd/flags.go b/lib/cmd/flags.go
index 882d805..e090a63 100644
--- a/lib/cmd/flags.go
+++ b/lib/cmd/flags.go
@@ -474,35 +474,41 @@ func (f *Flags) SetWithoutNull(b bool) {
f.ImportOptions.WithoutNull = b
}
-func (f *Flags) SetFormat(s string, outfile string) error {
- var fm Format
- var escape = txjson.Backslash
- var err error
+func (f *Flags) SetFormat(s string, outfile string, canOutputToPipe bool) error {
+ if len(s) < 1 {
+ if len(outfile) < 1 {
+ if canOutputToPipe {
+ f.ExportOptions.Format = CSV
+ } else {
+ f.ExportOptions.Format = TEXT
+ }
+ return nil
+ }
- switch s {
- case "":
switch strings.ToLower(filepath.Ext(outfile)) {
case CsvExt:
- fm = CSV
+ f.ExportOptions.Format = CSV
case TsvExt:
- fm = TSV
+ f.ExportOptions.Format = TSV
case JsonExt:
- fm = JSON
+ f.ExportOptions.Format = JSON
case JsonlExt:
- fm = JSONL
+ f.ExportOptions.Format = JSONL
case LtsvExt:
- fm = LTSV
+ f.ExportOptions.Format = LTSV
case GfmExt:
- fm = GFM
+ f.ExportOptions.Format = GFM
case OrgExt:
- fm = ORG
+ f.ExportOptions.Format = ORG
default:
- return nil
- }
- default:
- if fm, escape, err = ParseFormat(s, f.ExportOptions.JsonEscape); err != nil {
- return err
+ f.ExportOptions.Format = TEXT
}
+ return nil
+ }
+
+ fm, escape, err := ParseFormat(s, f.ExportOptions.JsonEscape)
+ if err != nil {
+ return err
}
f.ExportOptions.Format = fm
diff --git a/lib/cmd/flags_test.go b/lib/cmd/flags_test.go
index 9b84a04..2cf26a3 100644
--- a/lib/cmd/flags_test.go
+++ b/lib/cmd/flags_test.go
@@ -337,77 +337,87 @@ func TestFlags_SetWithoutNull(t *testing.T) {
func TestFlags_SetFormat(t *testing.T) {
flags, _ := NewFlags(nil)
- _ = flags.SetFormat("", "")
+ _ = flags.SetFormat("", "", false)
if flags.ExportOptions.Format != TEXT {
t.Errorf("format = %s, expect to set %s for empty string", flags.ExportOptions.Format, TEXT)
}
- _ = flags.SetFormat("", "foo.csv")
+ _ = flags.SetFormat("", "", true)
+ if flags.ExportOptions.Format != CSV {
+ t.Errorf("format = %s, expect to set %s for empty string", flags.ExportOptions.Format, CSV)
+ }
+
+ _ = flags.SetFormat("", "foo", true)
+ if flags.ExportOptions.Format != TEXT {
+ t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, TEXT, "foo")
+ }
+
+ _ = flags.SetFormat("", "foo.csv", false)
if flags.ExportOptions.Format != CSV {
t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, CSV, "foo.csv")
}
- _ = flags.SetFormat("", "foo.tsv")
+ _ = flags.SetFormat("", "foo.tsv", false)
if flags.ExportOptions.Format != TSV {
t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, TSV, "foo.tsv")
}
- _ = flags.SetFormat("", "foo.json")
+ _ = flags.SetFormat("", "foo.json", false)
if flags.ExportOptions.Format != JSON {
t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, JSON, "foo.json")
}
- _ = flags.SetFormat("", "foo.jsonl")
+ _ = flags.SetFormat("", "foo.jsonl", false)
if flags.ExportOptions.Format != JSONL {
t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, JSONL, "foo.jsonl")
}
- _ = flags.SetFormat("", "foo.ltsv")
+ _ = flags.SetFormat("", "foo.ltsv", false)
if flags.ExportOptions.Format != LTSV {
t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, LTSV, "foo.ltsv")
}
- _ = flags.SetFormat("", "foo.md")
+ _ = flags.SetFormat("", "foo.md", false)
if flags.ExportOptions.Format != GFM {
t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, GFM, "foo.md")
}
- _ = flags.SetFormat("", "foo.org")
+ _ = flags.SetFormat("", "foo.org", false)
if flags.ExportOptions.Format != ORG {
t.Errorf("format = %s, expect to set %s for empty string with file %q", flags.ExportOptions.Format, ORG, "foo.org")
}
- _ = flags.SetFormat("csv", "")
+ _ = flags.SetFormat("csv", "", false)
if flags.ExportOptions.Format != CSV {
t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, CSV, "csv")
}
- _ = flags.SetFormat("tsv", "")
+ _ = flags.SetFormat("tsv", "", false)
if flags.ExportOptions.Format != TSV {
t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, TSV, "tsv")
}
- _ = flags.SetFormat("fixed", "")
+ _ = flags.SetFormat("fixed", "", false)
if flags.ExportOptions.Format != FIXED {
t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, FIXED, "fixed")
}
- _ = flags.SetFormat("json", "")
+ _ = flags.SetFormat("json", "", false)
if flags.ExportOptions.Format != JSON {
t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, JSON, "json")
}
- _ = flags.SetFormat("jsonl", "")
+ _ = flags.SetFormat("jsonl", "", false)
if flags.ExportOptions.Format != JSONL {
t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, JSONL, "jsonl")
}
- _ = flags.SetFormat("ltsv", "")
+ _ = flags.SetFormat("ltsv", "", false)
if flags.ExportOptions.Format != LTSV {
t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, LTSV, "ltsv")
}
- _ = flags.SetFormat("jsonh", "")
+ _ = flags.SetFormat("jsonh", "", false)
if flags.ExportOptions.Format != JSON {
t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, JSON, "jsonh")
}
@@ -415,7 +425,7 @@ func TestFlags_SetFormat(t *testing.T) {
t.Errorf("json escape type = %v, expect to set %v for %s", flags.ExportOptions.JsonEscape, json.HexDigits, "jsonh")
}
- _ = flags.SetFormat("jsona", "")
+ _ = flags.SetFormat("jsona", "", false)
if flags.ExportOptions.Format != JSON {
t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, JSON, "jsona")
}
@@ -423,28 +433,28 @@ func TestFlags_SetFormat(t *testing.T) {
t.Errorf("json escape type = %v, expect to set %v for %s", flags.ExportOptions.JsonEscape, json.AllWithHexDigits, "jsonh")
}
- _ = flags.SetFormat("gfm", "")
+ _ = flags.SetFormat("gfm", "", false)
if flags.ExportOptions.Format != GFM {
t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, GFM, "gfm")
}
- _ = flags.SetFormat("org", "")
+ _ = flags.SetFormat("org", "", false)
if flags.ExportOptions.Format != ORG {
t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, ORG, "org")
}
- _ = flags.SetFormat("box", "")
+ _ = flags.SetFormat("box", "", false)
if flags.ExportOptions.Format != BOX {
t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, BOX, "box")
}
- _ = flags.SetFormat("text", "")
+ _ = flags.SetFormat("text", "", false)
if flags.ExportOptions.Format != TEXT {
t.Errorf("format = %s, expect to set %s for %s", flags.ExportOptions.Format, TEXT, "text")
}
expectErr := "format must be one of CSV|TSV|FIXED|JSON|JSONL|LTSV|GFM|ORG|BOX|TEXT"
- err := flags.SetFormat("error", "")
+ err := flags.SetFormat("error", "", false)
if err == nil {
t.Errorf("no error, want error %q for %s", expectErr, "error")
} else if err.Error() != expectErr {
diff --git a/lib/query/completer_readline.go b/lib/query/completer_readline.go
index 5856086..ad8a346 100644
--- a/lib/query/completer_readline.go
+++ b/lib/query/completer_readline.go
@@ -1,5 +1,4 @@
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package query
@@ -166,6 +165,8 @@ type Completer struct {
tokens []parser.Token
lastIdx int
selectIntoEnabled bool
+
+ isInAndAfterSelect bool
}
func NewCompleter(scope *ReferenceScope) *Completer {
@@ -1218,13 +1219,9 @@ func (c *Completer) SelectArgs(line string, origLine string, index int) readline
"LIMIT",
}, true)...)
customList = append(customList, c.SearchValues(line, origLine, index)...)
- customList = append(customList, c.aggregateFunctionCandidateList(line)...)
- customList = append(customList, c.analyticFunctionCandidateList(line)...)
}
} else {
customList = append(customList, c.SearchValues(line, origLine, index)...)
- customList = append(customList, c.aggregateFunctionCandidateList(line)...)
- customList = append(customList, c.analyticFunctionCandidateList(line)...)
}
if customList != nil {
@@ -1407,8 +1404,6 @@ func (c *Completer) SelectArgs(line string, origLine string, index int) readline
}
}
customList = append(customList, c.SearchValues(line, origLine, index)...)
- customList = append(customList, c.aggregateFunctionCandidateList(line)...)
- customList = append(customList, c.analyticFunctionCandidateList(line)...)
customList.Sort()
return keywords, customList, true
}
@@ -2179,6 +2174,12 @@ func (c *Completer) SearchValues(line string, origLine string, index int) readli
}
var cands readline.CandidateList
+
+ if c.isInAndAfterSelect {
+ cands = append(cands, c.aggregateFunctionCandidateList(line)...)
+ cands = append(cands, c.analyticFunctionCandidateList(line)...)
+ }
+
if len(searchWord) < 1 {
return cands
}
@@ -2534,6 +2535,8 @@ func (c *Completer) UpdateTokens(line string, origLine string) {
c.tokens = append(c.tokens, t)
}
+ c.setCursorIsInAndAfterSelect()
+
if 0 < len(c.tokens) {
c.tokens = c.tokens[c.searchStartIndex():]
}
@@ -2552,6 +2555,37 @@ func (c *Completer) SetLastIndex(line string) {
}
}
+func (c *Completer) setCursorIsInAndAfterSelect() {
+ c.isInAndAfterSelect = false
+
+ blockLevel := 0
+
+InAndAfterSelectLoop:
+ for i := len(c.tokens) - 1; i >= 0; i-- {
+ switch c.tokens[i].Token {
+ case ';',
+ parser.FROM, parser.WHERE, parser.GROUP, parser.HAVING, parser.LIMIT, parser.FETCH, parser.OFFSET,
+ parser.INTO:
+
+ break InAndAfterSelectLoop
+ case '(':
+ blockLevel--
+ case ')':
+ blockLevel++
+ case parser.SELECT:
+ if blockLevel <= 0 {
+ c.isInAndAfterSelect = true
+ break InAndAfterSelectLoop
+ }
+ case parser.BY:
+ if blockLevel <= 0 && 0 < i && c.tokens[i-1].Token == parser.ORDER {
+ c.isInAndAfterSelect = true
+ break InAndAfterSelectLoop
+ }
+ }
+ }
+}
+
func (c *Completer) searchStartIndex() int {
idx := 0
blockLevel := 0
diff --git a/lib/query/completer_readline_test.go b/lib/query/completer_readline_test.go
index 1a7675f..0098cb3 100644
--- a/lib/query/completer_readline_test.go
+++ b/lib/query/completer_readline_test.go
@@ -1,5 +1,4 @@
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package query
@@ -3692,6 +3691,7 @@ var completerSearchValuesTests = []completerTest{
OrigLine: "select c",
Index: 8,
Expect: readline.CandidateList{
+ {Name: []rune("COUNT()"), AppendSpace: false},
{Name: []rune("CASE"), AppendSpace: true},
{Name: []rune("CURSOR"), AppendSpace: true},
},
diff --git a/lib/query/session.go b/lib/query/session.go
index 3428aa8..2112f67 100644
--- a/lib/query/session.go
+++ b/lib/query/session.go
@@ -22,7 +22,7 @@ var (
stderr io.WriteCloser = os.Stderr
)
-func isReadableFromPipeOrRedirection(fp *os.File) bool {
+func isNamedPipe(fp *os.File) bool {
fi, err := fp.Stat()
if err == nil && (fi.Mode()&os.ModeNamedPipe != 0 || 0 < fi.Size()) {
return true
@@ -177,7 +177,9 @@ type Session struct {
outFile io.Writer
terminal VirtualTerminal
- CanReadStdin bool
+ CanReadStdin bool
+ CanOutputToPipe bool
+
stdinViewMap ViewMap
stdinLocker *StdinLocker
@@ -185,7 +187,8 @@ type Session struct {
}
func NewSession() *Session {
- canReadStdin := isReadableFromPipeOrRedirection(os.Stdin)
+ canReadStdin := isNamedPipe(os.Stdin)
+ canOutputToPipe := isNamedPipe(os.Stdout)
return &Session{
screenFd: screenFd,
@@ -195,7 +198,9 @@ func NewSession() *Session {
outFile: nil,
terminal: nil,
- CanReadStdin: canReadStdin,
+ CanReadStdin: canReadStdin,
+ CanOutputToPipe: canOutputToPipe,
+
stdinViewMap: NewViewMap(),
stdinLocker: NewStdinLocker(),
@@ -238,7 +243,7 @@ func (sess *Session) SetStdinContext(ctx context.Context, r io.ReadCloser) error
sess.CanReadStdin = false
if r != nil {
- if fp, ok := r.(*os.File); !ok || (ok && isReadableFromPipeOrRedirection(fp)) {
+ if fp, ok := r.(*os.File); !ok || (ok && isNamedPipe(fp)) {
sess.CanReadStdin = true
}
}
diff --git a/lib/query/terminal_functions.go b/lib/query/terminal_functions.go
index 01359fc..5f57120 100644
--- a/lib/query/terminal_functions.go
+++ b/lib/query/terminal_functions.go
@@ -1,4 +1,4 @@
-// +build !windows
+//go:build !windows
package query
diff --git a/lib/query/terminal_functions_windows.go b/lib/query/terminal_functions_windows.go
index 0dedbeb..bab0fa4 100644
--- a/lib/query/terminal_functions_windows.go
+++ b/lib/query/terminal_functions_windows.go
@@ -1,4 +1,4 @@
-// +build windows
+//go:build windows
package query
diff --git a/lib/query/terminal_general.go b/lib/query/terminal_general.go
index 508a95d..bca148e 100644
--- a/lib/query/terminal_general.go
+++ b/lib/query/terminal_general.go
@@ -1,4 +1,4 @@
-// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
+//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows
package query
diff --git a/lib/query/terminal_readline.go b/lib/query/terminal_readline.go
index aca2601..72fa81d 100644
--- a/lib/query/terminal_readline.go
+++ b/lib/query/terminal_readline.go
@@ -1,4 +1,4 @@
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
package query
diff --git a/lib/query/terminal_readline_test.go b/lib/query/terminal_readline_test.go
index 7406424..fe2584c 100644
--- a/lib/query/terminal_readline_test.go
+++ b/lib/query/terminal_readline_test.go
@@ -1,4 +1,4 @@
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
package query
diff --git a/lib/query/transaction.go b/lib/query/transaction.go
index 99f11fd..48560b3 100644
--- a/lib/query/transaction.go
+++ b/lib/query/transaction.go
@@ -437,7 +437,7 @@ func (tx *Transaction) setFlag(key string, value interface{}, outFile string) er
}
case cmd.FormatFlag:
if s, ok := value.(string); ok {
- err = tx.Flags.SetFormat(s, outFile)
+ err = tx.Flags.SetFormat(s, outFile, tx.Session.CanOutputToPipe)
} else {
err = errNotAllowdFlagFormat
}
diff --git a/main.go b/main.go
index 73f64f9..e8b5d14 100644
--- a/main.go
+++ b/main.go
@@ -107,8 +107,7 @@ func main() {
},
cli.StringFlag{
Name: "format, f",
- Value: "TEXT",
- Usage: "format of query results",
+ Usage: "format of query results. (default: \"CSV\" for output to pipe, \"TEXT\" otherwise)",
},
cli.StringFlag{
Name: "write-encoding, E",
@@ -402,13 +401,7 @@ func overwriteFlags(c *cli.Context, tx *query.Transaction) error {
_ = tx.SetFlag(cmd.StripEndingLineBreakFlag, c.GlobalBool("strip-ending-line-break"))
}
- setFormat := func() string {
- if c.GlobalIsSet("format") {
- return c.GlobalString("format")
- }
- return ""
- }()
- if err := tx.SetFormatFlag(setFormat, c.GlobalString("out")); err != nil {
+ if err := tx.SetFormatFlag(c.GlobalString("format"), c.GlobalString("out")); err != nil {
return query.NewIncorrectCommandUsageError(err.Error())
}