diff --git a/bolt.go b/bolt.go index 861581e..a0b4ca7 100644 --- a/bolt.go +++ b/bolt.go @@ -82,7 +82,7 @@ var _ loadedDatabase = &boltLoadedDatabase{} // interface assertion // -func (f *TMainForm) addDatabaseFromFile(path string) { +func (f *TMainForm) boltAddDatabaseFromFile(path string) { // TODO load in background thread to stop blocking the UI db, err := bbolt.Open(path, 0644, &bbolt.Options{Timeout: 1 * time.Second}) if err != nil { diff --git a/main.go b/main.go index 92b2096..60bf217 100644 --- a/main.go +++ b/main.go @@ -41,14 +41,19 @@ func (f *TMainForm) OnFormCreate(sender vcl.IObject) { mnuFile.SetCaption("File") mnuFileOpen := vcl.NewMenuItem(mnuFile) - mnuFileOpen.SetCaption("Open...") + mnuFileOpen.SetCaption("Open Bolt database...") mnuFileOpen.SetShortCutFromString("Ctrl+O") mnuFileOpen.SetOnClick(f.OnMnuFileOpenClick) mnuFile.Add(mnuFileOpen) + mnuFileSqliteOpen := vcl.NewMenuItem(mnuFile) + mnuFileSqliteOpen.SetCaption("Open SQLite database...") + mnuFileSqliteOpen.SetOnClick(f.OnMnuFileSqliteOpenClick) + mnuFile.Add(mnuFileSqliteOpen) + mnuFileSqliteMemory := vcl.NewMenuItem(mnuFile) mnuFileSqliteMemory.SetCaption("New SQLite in-memory database") - mnuFileSqliteMemory.SetOnClick(f.OnmnuFileSqliteMemoryClick) + mnuFileSqliteMemory.SetOnClick(f.OnMnuFileSqliteMemoryClick) mnuFile.Add(mnuFileSqliteMemory) mnuSep := vcl.NewMenuItem(mnuFile) @@ -116,21 +121,31 @@ func (f *TMainForm) OnFormCreate(sender vcl.IObject) { func (f *TMainForm) OnMnuFileOpenClick(sender vcl.IObject) { dlg := vcl.NewOpenDialog(f) dlg.SetTitle("Select a database file...") - dlg.SetFilter("Bolt database|*.db|SQLite database|*.db3|All files|*.*") + dlg.SetFilter("Bolt database|*.db|All files|*.*") ret := dlg.Execute() // Fake blocking if ret { - f.addDatabaseFromFile(dlg.FileName()) + f.boltAddDatabaseFromFile(dlg.FileName()) } } +func (f *TMainForm) OnMnuFileSqliteOpenClick(sender vcl.IObject) { + 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()) + } +} + +func (f *TMainForm) OnMnuFileSqliteMemoryClick(sender vcl.IObject) { + f.sqliteAddDatabaseFromFile(`:memory:`) +} + func (f *TMainForm) OnMnuFileExitClick(sender vcl.IObject) { os.Exit(0) } -func (f *TMainForm) OnmnuFileSqliteMemoryClick(sender vcl.IObject) { - f.SQLite_AddFromFile(`:memory:`) -} - func (f *TMainForm) OnNavChange(sender vcl.IObject, node *vcl.TTreeNode) { if node.Data() == nil { diff --git a/sqlite.go b/sqlite.go index 04d2045..0984552 100644 --- a/sqlite.go +++ b/sqlite.go @@ -49,10 +49,24 @@ func (ld *sqliteLoadedDatabase) RenderForNav(f *TMainForm, ndata *navData) { f.contentBox.SetEnabled(false) f.contentBox.Clear() - } else if ndata.bucketPath[0] == sqliteTablesCaption { + } else if len(ndata.bucketPath) == 2 && ndata.bucketPath[0] == sqliteTablesCaption { // Render for specific table - f.propertiesBox.SetText(fmt.Sprintf("Selected table %q", ndata.bucketPath[1])) - // Load schema + tableName := ndata.bucketPath[1] + + // Get some basic properties + r := ld.db.QueryRow(`SELECT sql FROM sqlite_schema WHERE name = ?;`, tableName) + var schemaStmt string + err := r.Scan(&schemaStmt) + if err != nil { + schemaStmt = fmt.Sprintf("* Failed to describe table %q: %s", tableName, err.Error()) + } + + // Display table properties + f.propertiesBox.SetText(fmt.Sprintf("Selected table %q\n\nSchema:\n\n%s", tableName, schemaStmt)) + + // Load column details + ld.db.Query(`pragma table_info(?)`, tableName) + // Select * with small limit f.contentBox.SetEnabled(false) f.contentBox.Clear() @@ -71,7 +85,7 @@ func (ld *sqliteLoadedDatabase) NavChildren(ndata *navData) ([]string, error) { return []string{sqliteTablesCaption}, nil } - if ndata.bucketPath[0] == sqliteTablesCaption { + if len(ndata.bucketPath) == 1 && ndata.bucketPath[0] == sqliteTablesCaption { rr, err := ld.db.Query(`SELECT name FROM sqlite_master WHERE type='table' ORDER BY name ASC;`) if err != nil { return nil, err @@ -95,6 +109,10 @@ func (ld *sqliteLoadedDatabase) NavChildren(ndata *navData) ([]string, error) { return gather, nil } + if len(ndata.bucketPath) == 2 { + return nil, nil // Never any deeper children + } + return nil, fmt.Errorf("unknown nav path %#v", ndata.bucketPath) } @@ -102,7 +120,7 @@ var _ loadedDatabase = &sqliteLoadedDatabase{} // interface assertion // -func (f *TMainForm) SQLite_AddFromFile(path string) { +func (f *TMainForm) sqliteAddDatabaseFromFile(path string) { // TODO load in background thread to stop blocking the UI db, err := sql.Open("sqlite3", path)