sqlite: basic integration for the cli driver
This commit is contained in:
parent
471737f421
commit
650c9e7183
13
db_sqlite.go
13
db_sqlite.go
@ -6,6 +6,8 @@ import (
|
||||
"path/filepath"
|
||||
"unsafe"
|
||||
|
||||
_ "yvbolt/sqliteclidriver"
|
||||
|
||||
"github.com/ying32/govcl/vcl"
|
||||
"github.com/ying32/govcl/vcl/types"
|
||||
)
|
||||
@ -102,7 +104,7 @@ func (ld *sqliteLoadedDatabase) RenderForNav(f *TMainForm, ndata *navData) {
|
||||
}
|
||||
|
||||
func (ld *sqliteLoadedDatabase) sqliteGetColumnNamesForTable(tableName string) ([]string, error) {
|
||||
colr, err := ld.db.Query(`SELECT name FROM pragma_table_info(?)`, tableName)
|
||||
colr, err := ld.db.Query(`SELECT name FROM pragma_table_info( ? )`, tableName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Query: %w", err)
|
||||
}
|
||||
@ -243,10 +245,15 @@ var _ loadedDatabase = &sqliteLoadedDatabase{} // interface assertion
|
||||
|
||||
//
|
||||
|
||||
func (f *TMainForm) sqliteAddDatabaseFromFile(path string) {
|
||||
func (f *TMainForm) sqliteAddDatabaseFromFile(path string, cliDriver bool) {
|
||||
|
||||
driver := "sqlite3"
|
||||
if cliDriver {
|
||||
driver = "sqliteclidriver"
|
||||
}
|
||||
|
||||
// TODO load in background thread to stop blocking the UI
|
||||
db, err := sql.Open("sqlite3", path)
|
||||
db, err := sql.Open(driver, path)
|
||||
if err != nil {
|
||||
vcl.ShowMessage(fmt.Sprintf("Failed to load database '%s': %s", path, err.Error()))
|
||||
return
|
||||
|
19
main.go
19
main.go
@ -21,8 +21,11 @@ const (
|
||||
type TMainForm struct {
|
||||
*vcl.TForm
|
||||
|
||||
ImageList *vcl.TImageList
|
||||
Menu *vcl.TMainMenu
|
||||
ImageList *vcl.TImageList
|
||||
Menu *vcl.TMainMenu
|
||||
|
||||
SQLiteUseCliDriver *vcl.TMenuItem
|
||||
|
||||
StatusBar *vcl.TStatusBar
|
||||
Buckets *vcl.TTreeView
|
||||
Tabs *vcl.TPageControl
|
||||
@ -103,6 +106,10 @@ func (f *TMainForm) OnFormCreate(sender vcl.IObject) {
|
||||
vcl_menuitem(mnuFileSqlite, "Open database...", imgDatabaseAdd, f.OnMnuFileSqliteOpenClick)
|
||||
vcl_menuitem(mnuFileSqlite, "New in-memory database", imgDatabaseAdd, f.OnMnuFileSqliteMemoryClick)
|
||||
|
||||
vcl_menuseparator(mnuFileSqlite)
|
||||
f.SQLiteUseCliDriver = vcl_menuitem(mnuFileSqlite, "Connect using CLI driver (experimental)", -1, nil)
|
||||
f.SQLiteUseCliDriver.SetAutoCheck(true)
|
||||
|
||||
//
|
||||
|
||||
vcl_menuseparator(mnuFile)
|
||||
@ -282,12 +289,14 @@ func (f *TMainForm) OnMnuFileBoltOpenReadonlyClick(sender vcl.IObject) {
|
||||
}
|
||||
|
||||
func (f *TMainForm) OnMnuFileSqliteOpenClick(sender vcl.IObject) {
|
||||
cliDriver := f.SQLiteUseCliDriver.Checked()
|
||||
|
||||
dlg := vcl.NewOpenDialog(f)
|
||||
dlg.SetTitle("Select a database file...")
|
||||
dlg.SetFilter("SQLite database|*.db;*.db3;*.sqlite;*.sqlite3|All files|*.*")
|
||||
ret := dlg.Execute() // Fake blocking
|
||||
if ret {
|
||||
f.sqliteAddDatabaseFromFile(dlg.FileName())
|
||||
f.sqliteAddDatabaseFromFile(dlg.FileName(), cliDriver)
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,7 +327,9 @@ func (f *TMainForm) OnMnuFilePebbleMemoryClick(sender vcl.IObject) {
|
||||
}
|
||||
|
||||
func (f *TMainForm) OnMnuFileSqliteMemoryClick(sender vcl.IObject) {
|
||||
f.sqliteAddDatabaseFromFile(`:memory:`)
|
||||
cliDriver := f.SQLiteUseCliDriver.Checked()
|
||||
|
||||
f.sqliteAddDatabaseFromFile(`:memory:`, cliDriver)
|
||||
}
|
||||
|
||||
func (f *TMainForm) OnMnuFileRedisConnectClick(sender vcl.IObject) {
|
||||
|
@ -1,7 +1,16 @@
|
||||
// sqliteclidriver is a database/sql driver for SQLite implemented on top of
|
||||
// the sqlite3 command-line tool. This allows it to be used over remote SSH
|
||||
// connections.
|
||||
//
|
||||
// Functionality is limited.
|
||||
//
|
||||
// Known caveats:
|
||||
// - Lexer only understands ? if it's separated by spaces
|
||||
// - Bad error handling
|
||||
// - Few supported types
|
||||
// - Has to escape parameters for CLI instead of preparing them, so not safe for untrusted usage
|
||||
// - No context handling
|
||||
// - No way to configure sqlite3 command line path
|
||||
package sqliteclidriver
|
||||
|
||||
import (
|
||||
|
@ -14,39 +14,44 @@ func TestSqliteCliDriver(t *testing.T) {
|
||||
_, err = db.Exec(`CREATE TABLE my_test_table ( id INTEGER PRIMARY KEY, extra TEXT NOT NULL );`)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = db.Exec(`INSERT INTO my_test_table (id, extra) VALUES (1337, "abcdef"), (9001, "whoop");`)
|
||||
_, err = db.Exec(`INSERT INTO my_test_table (id, extra) VALUES ( ? , ? ), ( ? , ? );`, 1337, "abcdef", 9001, "whoop")
|
||||
require.NoError(t, err)
|
||||
|
||||
res, err := db.Query(`SELECT * FROM my_test_table ORDER BY id ASC;`)
|
||||
require.NoError(t, err)
|
||||
// Repeat this part to ensure we can make followup queries on the same connection
|
||||
for i := 0; i < 3; i++ {
|
||||
|
||||
cols, err := res.Columns()
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, cols, []string{"id", "extra"})
|
||||
res, err := db.Query(`SELECT * FROM my_test_table ORDER BY id ASC;`)
|
||||
require.NoError(t, err)
|
||||
|
||||
var rowCount int = 0
|
||||
cols, err := res.Columns()
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, cols, []string{"id", "extra"})
|
||||
|
||||
for res.Next() {
|
||||
rowCount++
|
||||
var rowCount int = 0
|
||||
|
||||
var idVal int
|
||||
var extraVal string
|
||||
err = res.Scan(&idVal, &extraVal)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
for res.Next() {
|
||||
rowCount++
|
||||
|
||||
var idVal int
|
||||
var extraVal string
|
||||
err = res.Scan(&idVal, &extraVal)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
switch rowCount {
|
||||
case 1:
|
||||
require.EqualValues(t, 1337, idVal)
|
||||
require.EqualValues(t, "abcdef", extraVal)
|
||||
|
||||
case 2:
|
||||
require.EqualValues(t, 9001, idVal)
|
||||
require.EqualValues(t, "whoop", extraVal)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
switch rowCount {
|
||||
case 1:
|
||||
require.EqualValues(t, 1337, idVal)
|
||||
require.EqualValues(t, "abcdef", extraVal)
|
||||
require.Equal(t, rowCount, 2)
|
||||
|
||||
case 2:
|
||||
require.EqualValues(t, 9001, idVal)
|
||||
require.EqualValues(t, "whoop", extraVal)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
require.Equal(t, rowCount, 2)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user