Skip to content

Commit

Permalink
Merge pull request #142 from svanharmelen/feat/config
Browse files Browse the repository at this point in the history
Introduce a way to support user defined configurations
  • Loading branch information
jorgerojas26 authored Jan 3, 2025
2 parents fec43c9 + d0acf68 commit 20f3e82
Show file tree
Hide file tree
Showing 16 changed files with 190 additions and 162 deletions.
19 changes: 19 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (

"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"

"github.com/jorgerojas26/lazysql/models"
)

var (
Expand All @@ -19,6 +21,7 @@ var (
type Application struct {
*tview.Application

config *Config
context context.Context
cancelFn context.CancelFunc
waitGroup sync.WaitGroup
Expand All @@ -35,6 +38,7 @@ func init() {

App = &Application{
Application: tview.NewApplication(),
config: defaultConfig(),
context: ctx,
cancelFn: cancel,
}
Expand Down Expand Up @@ -68,6 +72,21 @@ func (a *Application) Context() context.Context {
return a.context
}

// Config returns the application configuration.
func (a *Application) Config() *models.AppConfig {
return a.config.AppConfig
}

// Connections returns the database connections.
func (a *Application) Connections() []models.Connection {
return a.config.Connections
}

// SaveConnections saves the database connections.
func (a *Application) SaveConnections(connections []models.Connection) error {
return a.config.SaveConnections(connections)
}

// Register adds a task to the wait group and returns a
// function that decrements the task count when called.
//
Expand Down
110 changes: 110 additions & 0 deletions app/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package app

import (
"fmt"
"net/url"
"os"
"path/filepath"

"github.com/pelletier/go-toml/v2"

"github.com/jorgerojas26/lazysql/drivers"
"github.com/jorgerojas26/lazysql/models"
)

type Config struct {
AppConfig *models.AppConfig `toml:"application"`
Connections []models.Connection `toml:"database"`
}

func defaultConfig() *Config {
return &Config{
AppConfig: &models.AppConfig{
DefaultPageSize: 300,
},
}
}

func defaultConfigFile() (string, error) {
configDir := os.Getenv("XDG_CONFIG_HOME")
if configDir == "" {
dir, err := os.UserConfigDir()
if err != nil {
return "", err
}
configDir = dir
}
return filepath.Join(configDir, "lazysql", "config.toml"), nil
}

func LoadConfig() error {
configFile, err := defaultConfigFile()
if err != nil {
return err
}

file, err := os.ReadFile(configFile)
if err != nil && !os.IsNotExist(err) {
return err
}

err = toml.Unmarshal(file, App.config)
if err != nil {
return err
}

for i, conn := range App.config.Connections {
App.config.Connections[i].URL = parseConfigURL(&conn)
}

return nil
}

func (c *Config) SaveConnections(connections []models.Connection) error {
c.Connections = connections

configFile, err := defaultConfigFile()
if err != nil {
return err
}

if err = os.MkdirAll(filepath.Dir(configFile), 0o755); err != nil {
return err
}

file, err := os.Create(configFile)
if err != nil {
return err
}
defer file.Close()

return toml.NewEncoder(file).Encode(c)
}

// parseConfigURL automatically generates the URL from the connection struct
// if the URL is empty. It is useful for handling usernames and passwords with
// special characters. NOTE: Only MSSQL is supported for now!
func parseConfigURL(conn *models.Connection) string {
if conn.URL != "" {
return conn.URL
}

// Only MSSQL is supported for now.
if conn.Provider != drivers.DriverMSSQL {
return conn.URL
}

user := url.QueryEscape(conn.Username)
pass := url.QueryEscape(conn.Password)

return fmt.Sprintf(
"%s://%s:%s@%s:%s?database=%s%s",
conn.Provider,
user,
pass,
conn.Hostname,
conn.Port,
conn.DBName,
conn.URLParams,
)
}
2 changes: 1 addition & 1 deletion components/arg_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func InitFromArg(connectionString string) error {
if err != nil {
return fmt.Errorf("Could not connect to database %s: %s", connectionString, err)
}
MainPages.AddAndSwitchToPage(connection.URL, NewHomePage(connection, newDBDriver).Flex, true)
mainPages.AddAndSwitchToPage(connection.URL, NewHomePage(connection, newDBDriver).Flex, true)

return nil
}
10 changes: 5 additions & 5 deletions components/connection_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (form *ConnectionForm) inputCapture(connectionPages *models.ConnectionPages
return event
}

databases, _ := helpers.LoadConnections()
databases := app.App.Connections()
newDatabases := make([]models.Connection, len(databases))

DBName := strings.Split(parsed.Normalize(",", "NULL", 0), ",")[3]
Expand All @@ -115,15 +115,15 @@ func (form *ConnectionForm) inputCapture(connectionPages *models.ConnectionPages
case actionNewConnection:

newDatabases = append(databases, parsedDatabaseData)
err := helpers.SaveConnectionConfig(newDatabases)
err := app.App.SaveConnections(newDatabases)
if err != nil {
form.StatusText.SetText(err.Error()).SetTextStyle(tcell.StyleDefault.Foreground(tcell.ColorRed))
return event
}

case actionEditConnection:
newDatabases = make([]models.Connection, len(databases))
row, _ := ConnectionListTable.GetSelection()
row, _ := connectionsTable.GetSelection()

for i, database := range databases {
if i == row {
Expand All @@ -143,15 +143,15 @@ func (form *ConnectionForm) inputCapture(connectionPages *models.ConnectionPages
}
}

err := helpers.SaveConnectionConfig(newDatabases)
err := app.App.SaveConnections(newDatabases)
if err != nil {
form.StatusText.SetText(err.Error()).SetTextStyle(tcell.StyleDefault.Foreground(tcell.ColorRed))
return event

}
}

ConnectionListTable.SetConnections(newDatabases)
connectionsTable.SetConnections(newDatabases)
connectionPages.SwitchToPage(pageNameConnectionSelection)

} else if event.Key() == tcell.KeyF2 {
Expand Down
28 changes: 13 additions & 15 deletions components/connection_selection.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ type ConnectionSelection struct {
StatusText *tview.TextView
}

var ConnectionListTable = NewConnectionsTable()

func NewConnectionSelection(connectionForm *ConnectionForm, connectionPages *models.ConnectionPages) *ConnectionSelection {
wrapper := tview.NewFlex()

Expand Down Expand Up @@ -66,7 +64,7 @@ func NewConnectionSelection(connectionForm *ConnectionForm, connectionPages *mod
statusText := tview.NewTextView()
statusText.SetBorderPadding(1, 1, 0, 0)

wrapper.AddItem(ConnectionListTable, 0, 1, true)
wrapper.AddItem(NewConnectionsTable(), 0, 1, true)
wrapper.AddItem(statusText, 4, 0, false)
wrapper.AddItem(buttonsWrapper, 3, 0, false)

Expand All @@ -76,12 +74,12 @@ func NewConnectionSelection(connectionForm *ConnectionForm, connectionPages *mod
}

wrapper.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
connections := ConnectionListTable.GetConnections()
connections := connectionsTable.GetConnections()

command := app.Keymaps.Group(app.ConnectionGroup).Resolve(event)

if len(connections) != 0 {
row, _ := ConnectionListTable.GetSelection()
row, _ := connectionsTable.GetSelection()
selectedConnection := connections[row]

switch command {
Expand All @@ -99,23 +97,23 @@ func NewConnectionSelection(connectionForm *ConnectionForm, connectionPages *mod
confirmationModal := NewConfirmationModal("")

confirmationModal.SetDoneFunc(func(_ int, buttonLabel string) {
MainPages.RemovePage(pageNameConfirmation)
mainPages.RemovePage(pageNameConfirmation)
confirmationModal = nil

if buttonLabel == "Yes" {
newConnections := append(connections[:row], connections[row+1:]...)

err := helpers.SaveConnectionConfig(newConnections)
err := app.App.SaveConnections(newConnections)
if err != nil {
ConnectionListTable.SetError(err)
connectionsTable.SetError(err)
} else {
ConnectionListTable.SetConnections(newConnections)
connectionsTable.SetConnections(newConnections)
}

}
})

MainPages.AddPage(pageNameConfirmation, confirmationModal, true, true)
mainPages.AddPage(pageNameConfirmation, confirmationModal, true, true)

return nil
}
Expand All @@ -141,8 +139,8 @@ func NewConnectionSelection(connectionForm *ConnectionForm, connectionPages *mod
}

func (cs *ConnectionSelection) Connect(connection models.Connection) *tview.Application {
if MainPages.HasPage(connection.Name) {
MainPages.SwitchToPage(connection.Name)
if mainPages.HasPage(connection.Name) {
mainPages.SwitchToPage(connection.Name)
return App.Draw()
}

Expand Down Expand Up @@ -204,16 +202,16 @@ func (cs *ConnectionSelection) Connect(connection models.Connection) *tview.Appl
return App.Draw()
}

selectedRow, selectedCol := ConnectionListTable.GetSelection()
cell := ConnectionListTable.GetCell(selectedRow, selectedCol)
selectedRow, selectedCol := connectionsTable.GetSelection()
cell := connectionsTable.GetCell(selectedRow, selectedCol)
cell.SetText(fmt.Sprintf("[green]* %s", cell.Text))
cs.StatusText.SetText("")

newHome := NewHomePage(connection, newDBDriver)
newHome.Tree.SetCurrentNode(newHome.Tree.GetRoot())
newHome.Tree.Wrapper.SetTitle(connection.Name)

MainPages.AddAndSwitchToPage(connection.Name, newHome, true)
mainPages.AddAndSwitchToPage(connection.Name, newHome, true)
App.SetFocus(newHome.Tree)

return App.Draw()
Expand Down
16 changes: 5 additions & 11 deletions components/connections_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"github.com/rivo/tview"

"github.com/jorgerojas26/lazysql/app"
"github.com/jorgerojas26/lazysql/helpers"
"github.com/jorgerojas26/lazysql/models"
)

Expand All @@ -17,6 +16,8 @@ type ConnectionsTable struct {
connections []models.Connection
}

var connectionsTable *ConnectionsTable

func NewConnectionsTable() *ConnectionsTable {
wrapper := tview.NewFlex()

Expand All @@ -33,23 +34,16 @@ func NewConnectionsTable() *ConnectionsTable {
table.SetSelectedStyle(tcell.StyleDefault.Foreground(app.Styles.SecondaryTextColor).Background(tview.Styles.PrimitiveBackgroundColor))

wrapper.AddItem(table, 0, 1, true)
table.SetConnections(app.App.Connections())

connections, err := helpers.LoadConnections()

if err != nil {
table.SetError(err)
} else {
table.SetConnections(connections)
}
connectionsTable = table

return table
return connectionsTable
}

func (ct *ConnectionsTable) AddConnection(connection models.Connection) {
rowCount := ct.GetRowCount()

ct.SetCellSimple(rowCount, 0, connection.Name)

ct.connections = append(ct.connections, connection)
}

Expand Down
2 changes: 1 addition & 1 deletion components/help_modal.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func NewHelpModal() *HelpModal {
table.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
command := app.Keymaps.Group(app.HomeGroup).Resolve(event)
if command == commands.Quit || command == commands.HelpPopup || event.Key() == tcell.KeyEsc {
MainPages.RemovePage(pageNameHelp)
mainPages.RemovePage(pageNameHelp)
}
return event
})
Expand Down
Loading

0 comments on commit 20f3e82

Please sign in to comment.