Skip to content

Commit

Permalink
support for saving file manuall
Browse files Browse the repository at this point in the history
  • Loading branch information
napisani committed Mar 5, 2024
1 parent 8c3b4cd commit 3437135
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 23 deletions.
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,20 @@ Plug 'napisani/nvim-dadbod-bg', { 'do': './install.sh' }
5. You should see the results of your query in the browser. As you run more queries, the results will update in the browser.


If you want to send results manually to nvim-dadbod-bg, you can use the following command:
```vim
" the current file will be sent to the webserver
:DBBGSetFile
" send a file with an absolute path to the webserver
:DBBGSetFile /absolute/path/to/query_results.json
" send a file with a relative path (from nvim's cwd) to the webserver
:DBBGSetFile relative/path/to/query_results.json
```


### Development

This plugin consists of three parts:
Expand Down Expand Up @@ -165,7 +179,7 @@ The contents of this message does not contain the actual query results. The clie
- returns the query results in the following format:
```json
{
"type": "string", // json or dbout
"type": "string", // json, csv or dbout
"parsedAt": "number", // the epoch time in seconds that the query results were parsed
"content": "string" // a string representation of the raw query results
}
Expand All @@ -176,7 +190,7 @@ The contents of this message does not contain the actual query results. The clie
- returns the parsed query results in the following format:
```json
{
"type": "string", // json or dbout
"type": "string", // json, csv or dbout
"parsedAt": "number", // the epoch time in seconds that the query results were parsed
"content": [
{
Expand Down
55 changes: 55 additions & 0 deletions csv_parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package main

import (
"encoding/csv"
"io"
"log"
"strings"
)


func ParseCsvSubQueryResults(content string) []SubQueryResults {
return []SubQueryResults{ParseCsvSubQueryResult(content)}
}

func ParseCsvSubQueryResult(content string) SubQueryResults {
reader := csv.NewReader(strings.NewReader(content))
rows := make([]map[string]interface{}, 0)
var headerAcc HeaderAccumulator
var headers []string

first := true
for {
record, err := reader.Read()
if err == io.EOF {
break
}
if err != nil {
log.Println("an error occurred parsing a csv line", err)
}
if first {
headerAcc = *NewHeaderAccumulator(true, record)
headers = record
first = false
continue
}

if len(record) != len(headers) {
log.Println("csv record has different number of columns than header")
continue
}
row := make(map[string]interface{})
for i, header := range headers {
row[header] = record[i]
}

headerAcc.inspectRow(row)
rows = append(rows, row)
}
return SubQueryResults{
Header: headerAcc.ToDataHeaders(),
Content: rows,
Prefix: "",
Type: "csv",
}
}
42 changes: 42 additions & 0 deletions csv_parse_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package main

import (
"reflect"
"testing"
)

func TestParseCsvSubQueryResult(t *testing.T) {
content := "name,age,email\nJohn,25,john@example.com\nJane,30,jane@example.com"
expectedHeader := []DataHeader{
DataHeader{Name: "name", InferredType: "string"},
DataHeader{Name: "age", InferredType: "number"},
DataHeader{Name: "email", InferredType: "string"},
}
expectedContent := []map[string]interface{}{
{"name": "John", "age": "25", "email": "john@example.com"},
{"name": "Jane", "age": "30", "email": "jane@example.com"},
}

result := ParseCsvSubQueryResult(content)

for i, header := range result.Header {
if header.Name != expectedHeader[i].Name {
t.Errorf("ParseCsvSubQueryResult() failed, expected header name: %s, got: %s", expectedHeader[i].Name, header.Name)
}
if header.InferredType != expectedHeader[i].InferredType {
t.Errorf("ParseCsvSubQueryResult() failed, expected header inferred type: %s, got: %s", expectedHeader[i].InferredType, header.InferredType)
}
}

if !reflect.DeepEqual(result.Content, expectedContent) {
t.Errorf("ParseCsvSubQueryResult() failed, expected content: %v, got: %v", expectedContent, result.Content)
}

if result.Prefix != "" {
t.Errorf("ParseCsvSubQueryResult() failed, expected prefix to be empty, got: %s", result.Prefix)
}

if result.Type != "csv" {
t.Errorf("ParseCsvSubQueryResult() failed, expected type to be 'csv', got: %s", result.Type)
}
}
5 changes: 5 additions & 0 deletions header_acc.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func (h *HeaderAccumulator) addHeader(name string) {
}
}


func (h *HeaderAccumulator) ToDataHeaders() DataHeaders {
headers := DataHeaders{}
for _, name := range h.headerOrder {
Expand All @@ -107,3 +108,7 @@ func (h *HeaderAccumulator) ToDataHeaders() DataHeaders {
}
return headers
}

func (h *HeaderAccumulator) Count() int {
return len(h.headers)
}
27 changes: 27 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ type FileAutocmdEval struct {
Filename string `eval:"expand('<amatch>:h')"`
}

type FileManualCmdEval struct {
Cwd string `msgpack:",array"`
File string
}

func initLog(debug bool) {
tmpDir := os.TempDir()
var logPath string
Expand Down Expand Up @@ -50,6 +55,28 @@ func main() {

go StartServer(port, altRootDir)
plugin.Main(func(p *plugin.Plugin) error {

p.HandleCommand(&plugin.CommandOptions{Name: "DBBGSetFile", NArgs: "?", Eval: "[getcwd(), expand('%:p')]"},
func(args []string, eval *FileManualCmdEval) {
if len(args) > 0 && len(args[0]) > 0 {
file := args[0]
if file[0] == '/' || file[0] == '~' {
log.Print("DBBGSetFile - using provided absolute path: " + file)
SetQueryResults(file)
BroadcastQueryResults()
} else {
file = path.Join(eval.Cwd, file)
log.Print("DBBGSetFile - using provided file and relative path: " + file)
SetQueryResults(file)
BroadcastQueryResults()
}
} else {
log.Print("DBBGSetFile - no args provided, using current file: " + eval.File)
SetQueryResults(eval.File)
BroadcastQueryResults()
}
})

p.HandleAutocmd(&plugin.AutocmdOptions{Event: "User", Group: "ExmplNvGoClientGrp", Pattern: "*DBExecutePost", Eval: "*"},
func(eval *FileAutocmdEval) {
log.Print("DBExecutePost - wrote file: " + eval.Filename)
Expand Down
3 changes: 1 addition & 2 deletions plugin/nvim-go-client.vim
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,5 @@ call remote#host#Register('nvim_dadbod_bg', 'x', function('s:Sart_nvim_dadbog_bg
" the 'host' name is 'nvim_dadbod_bg'.
call remote#host#RegisterPlugin('nvim_dadbod_bg', '0', [
\ {'type': 'autocmd', 'name': 'User', 'sync': 0, 'opts': {'eval': '{''Filename'': expand(''<amatch>:h'')}', 'group': 'ExmplNvGoClientGrp', 'pattern': '*DBExecutePost'}},
\ {'type': 'command', 'name': 'DBBGSetFile', 'sync': 0, 'opts': {'eval': '[getcwd(), expand(''%:p'')]', 'nargs': '?'}},
\ ])


45 changes: 28 additions & 17 deletions query-result.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"errors"
"io/ioutil"
"log"
"strings"
"path/filepath"
"time"
)

Expand Down Expand Up @@ -41,24 +41,22 @@ type DataHeaders []DataHeader
var rawQueryResults RawQueryResults

func SetQueryResults(file string) {
var t string
if strings.HasSuffix(file, ".json") {
t = "json"
} else if strings.HasSuffix(file, ".dbout") {
t = "dbout"
} else {
t := filepath.Ext(file)
if t == "" || t == "." {
t = "txt"
}
} else {
t = t[1:]
}

content, err := ioutil.ReadFile(file)
if err != nil {
log.Fatal(err)
}

rawQueryResults = RawQueryResults{
t,
string(content),
time.Now().Unix(),
} else {
rawQueryResults = RawQueryResults{
t,
string(content),
time.Now().Unix(),
}
}
}

Expand All @@ -73,13 +71,26 @@ func GetTypedQueryResults() (TypedQueryResults, error) {
log.Println("Parsing json")
subQueryResults := ParseJsonSubQueryResults(content)
log.Println("Parsed json successfully")
return TypedQueryResults{Type: "json", Content: subQueryResults, ParsedAt: rawQueryResults.ParsedAt}, nil
return TypedQueryResults{
Type: "json",
Content: subQueryResults,
ParsedAt: rawQueryResults.ParsedAt}, nil
} else if rawQueryResults.Type == "csv" {
log.Println("Parsing csv")
subQueryResults := ParseCsvSubQueryResults(content)
log.Println("Parsed csv successfully")
return TypedQueryResults{
Type: "csv",
Content: subQueryResults,
ParsedAt: rawQueryResults.ParsedAt}, nil
} else if rawQueryResults.Type == "dbout" {
log.Println("Parsing dbout")
subQueryResults := ParseDBOutSubQueryResults(content)
log.Println("Parsed dbout successfully")
return TypedQueryResults{Type: "dbout",
Content: subQueryResults, ParsedAt: rawQueryResults.ParsedAt}, nil
return TypedQueryResults{
Type: "dbout",
Content: subQueryResults,
ParsedAt: rawQueryResults.ParsedAt}, nil
}

return TypedQueryResults{}, errors.New("Unknown type")
Expand Down
5 changes: 5 additions & 0 deletions test_data/csv.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
name,birth date,fav number
dave,1980-01-01,7
jane,1981-02-02,8
fred,1982-03-03,9
mary,1983-04-04,42
16 changes: 16 additions & 0 deletions test_data/json.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "John Doe",
"age": 30,
"email": "johndoe@example.com",
"address": {
"street": "123 Main St",
"city": "New York",
"state": "NY",
"zip": "10001"
},
"interests": [
"programming",
"reading",
"traveling"
]
}
2 changes: 1 addition & 1 deletion web/src/Results.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export function Results({
/>
)
}
if (type === 'dbout') {
if (type === 'dbout' || type === 'csv') {
return (
<DBOutSubSection
key={index}
Expand Down
2 changes: 1 addition & 1 deletion web/src/query-results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface TypedQueryResults {
receivedAt: number
}

export type OutputType = 'json' | 'dbout'
export type OutputType = 'json' | 'dbout' | 'csv'

export type DataType = 'string' | 'number' | 'boolean' | 'date' | 'object'

Expand Down

0 comments on commit 3437135

Please sign in to comment.