// Debby is a command line tool that links your dolt database to visidata package main import ( "fmt" "os" "os/exec" "strings" "sync" ) var once = sync.Once{} func main() { var choice int var table string var query string var args []string if len(os.Args) > 1 { switch os.Args[1] { case "ls": // List tables choice = 1 case "edit": // Import table choice = 3 table = os.Args[2] case "run": // Run query choice = 2 query = strings.Join(os.Args[2:], " ") case "help": // Print help str := `debby is a command line tool that links your dolt database to visidata Usage: debby [command] [arguments] The commands are: ls List tables edit Import table run Run query help Print help Runnning debby without any arguments will start debby in interactive mode. Running debby with any other arguments will run it as a dolt command.` fmt.Println(str) return } } // Menu loop. 1. Read tale names 2. Run query 3. Run and save query 4. Execute Dolt command 5. Exit for { // Execute choice switch choice { case 1: // Read table names ReadTableNames() case 2: if query == "" { // Request query fmt.Print("Enter your query: ") fmt.Scanln(&query) } // Table name will be empty. Run query RunSQL(query, "") case 3: if table == "" { // Request table name fmt.Print("Enter your table name: ") fmt.Scanln(&table) } // Run query RunSQL("select * from "+table+";", table) case 4: if len(args) == 0 { // Request command fmt.Print("dolt ") fmt.Scanln(&args) } // Execute command ExecuteDoltCommand(args...) case 5: // Exit return default: // Reset choice choice = 0 // Print menu fmt.Println("1. Read table names") fmt.Println("2. Run query") fmt.Println("3. Edit table") fmt.Println("4. Execute Dolt command") fmt.Println("5. Exit") fmt.Print("Enter your choice: ") // Read user input fmt.Scanln(&choice) } // Reset all variables except choice table = "" query = "" args = []string{} } } func ExecuteDoltCommand(args ...string) { cmd := exec.Command("dolt", args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin cmd.Run() } func SaveToTable(table, file string) error { // Run dolt table import -r table file cmd := exec.Command("dolt", "table", "import", "-r", table, file) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin return cmd.Run() } func ReadTableNames() { // Run dolt ls cmd := exec.Command("dolt", "ls") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin cmd.Run() } func RunSQL(query, table string) error { // Create a temporary file to open in visidata f, err := os.CreateTemp("", "debby-*.sql") if err != nil { return err } defer os.Remove(f.Name()) // Run the query and write the output to the file cmd := exec.Command("dolt", "sql", "-q", query, "-r", "csv") cmd.Stdout = f err = cmd.Run() if err != nil { return err } // Open the file in visidata OpenVisidata(f.Name(), "-f", "csv") // If table is not empty, save the file to the table if table != "" { err = SaveToTable(table, f.Name()) if err != nil { return err } } // Read the file back into memory return nil } func OpenVisidata(args ...string) { vdcmd := os.Getenv("EDITOR") once.Do(func() { // run with --version and check if it returns saul.pw/VisiData, if not try the same with visidata instead for _, cmd := range []string{"vd", "visidata"} { out, err := exec.Command(cmd, "--version").Output() if err != nil { continue } if strings.Contains(string(out), "saul.pw/VisiData") { vdcmd = cmd break } } }) cmd := exec.Command(vdcmd, args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin cmd.Run() }