package app import ( "context" "time" "go.uber.org/zap" "uzdb/internal/config" "uzdb/internal/database" "uzdb/internal/handler" "uzdb/internal/models" "uzdb/internal/services" ) // App is the main application structure for Wails bindings type App struct { ctx context.Context config *config.Config connectionSvc *services.ConnectionService querySvc *services.QueryService httpServer *handler.HTTPServer shutdownFunc context.CancelFunc } // NewApp creates a new App instance func NewApp() *App { return &App{} } // Initialize initializes the application with all services func (a *App) Initialize( cfg *config.Config, connectionSvc *services.ConnectionService, querySvc *services.QueryService, httpServer *handler.HTTPServer, ) { a.config = cfg a.connectionSvc = connectionSvc a.querySvc = querySvc a.httpServer = httpServer } // OnStartup is called when the app starts (public method for Wails) func (a *App) OnStartup(ctx context.Context) { a.ctx = ctx config.GetLogger().Info("Wails application started") } // GetConnections returns all user connections // Wails binding: frontend can call window.go.app.GetConnections() func (a *App) GetConnections() []models.UserConnection { if a.connectionSvc == nil { return []models.UserConnection{} } connections, err := a.connectionSvc.GetAllConnections(a.ctx) if err != nil { config.GetLogger().Error("failed to get connections", zap.Error(err)) return []models.UserConnection{} } return connections } // CreateConnection creates a new database connection // Returns error message or empty string on success func (a *App) CreateConnection(conn models.CreateConnectionRequest) string { if a.connectionSvc == nil { return "Service not initialized" } _, err := a.connectionSvc.CreateConnection(a.ctx, &conn) if err != nil { config.GetLogger().Error("failed to create connection", zap.Error(err)) return err.Error() } return "" } // UpdateConnection updates an existing database connection // Returns error message or empty string on success func (a *App) UpdateConnection(conn models.UserConnection) string { if a.connectionSvc == nil { return "Service not initialized" } req := &models.UpdateConnectionRequest{ Name: conn.Name, Type: conn.Type, Host: conn.Host, Port: conn.Port, Username: conn.Username, Password: conn.Password, Database: conn.Database, SSLMode: conn.SSLMode, Timeout: conn.Timeout, } _, err := a.connectionSvc.UpdateConnection(a.ctx, conn.ID, req) if err != nil { config.GetLogger().Error("failed to update connection", zap.Error(err)) return err.Error() } return "" } // DeleteConnection deletes a database connection // Returns error message or empty string on success func (a *App) DeleteConnection(id string) string { if a.connectionSvc == nil { return "Service not initialized" } err := a.connectionSvc.DeleteConnection(a.ctx, id) if err != nil { config.GetLogger().Error("failed to delete connection", zap.Error(err)) return err.Error() } return "" } // TestConnection tests a database connection // Returns (success, error_message) func (a *App) TestConnection(id string) (bool, string) { if a.connectionSvc == nil { return false, "Service not initialized" } result, err := a.connectionSvc.TestConnection(a.ctx, id) if err != nil { config.GetLogger().Error("failed to test connection", zap.Error(err)) return false, err.Error() } return result.Success, result.Message } // ExecuteQuery executes a SQL query on a connection // Returns query result or error message func (a *App) ExecuteQuery(connectionID, sql string) (*models.QueryResult, string) { if a.connectionSvc == nil { return nil, "Service not initialized" } result, err := a.connectionSvc.ExecuteQuery(a.ctx, connectionID, sql) if err != nil { config.GetLogger().Error("failed to execute query", zap.String("connection_id", connectionID), zap.String("sql", sql), zap.Error(err)) return nil, err.Error() } return result, "" } // GetTables returns all tables for a connection func (a *App) GetTables(connectionID string) ([]models.Table, string) { if a.connectionSvc == nil { return []models.Table{}, "Service not initialized" } tables, err := a.connectionSvc.GetTables(a.ctx, connectionID) if err != nil { config.GetLogger().Error("failed to get tables", zap.String("connection_id", connectionID), zap.Error(err)) return []models.Table{}, err.Error() } return tables, "" } // GetTableData returns data from a table func (a *App) GetTableData(connectionID, tableName string, limit, offset int) (*models.QueryResult, string) { if a.connectionSvc == nil { return nil, "Service not initialized" } result, err := a.connectionSvc.GetTableData(a.ctx, connectionID, tableName, limit, offset) if err != nil { config.GetLogger().Error("failed to get table data", zap.String("connection_id", connectionID), zap.String("table", tableName), zap.Error(err)) return nil, err.Error() } return result, "" } // GetTableStructure returns the structure of a table func (a *App) GetTableStructure(connectionID, tableName string) (*models.TableStructure, string) { if a.connectionSvc == nil { return nil, "Service not initialized" } structure, err := a.connectionSvc.GetTableStructure(a.ctx, connectionID, tableName) if err != nil { config.GetLogger().Error("failed to get table structure", zap.String("connection_id", connectionID), zap.String("table", tableName), zap.Error(err)) return nil, err.Error() } return structure, "" } // GetQueryHistory returns query history with pagination func (a *App) GetQueryHistory(connectionID string, page, pageSize int) ([]models.QueryHistory, int64, string) { if a.querySvc == nil { return []models.QueryHistory{}, 0, "Service not initialized" } history, total, err := a.querySvc.GetQueryHistory(a.ctx, connectionID, page, pageSize) if err != nil { config.GetLogger().Error("failed to get query history", zap.Error(err)) return []models.QueryHistory{}, 0, err.Error() } return history, total, "" } // GetSavedQueries returns all saved queries func (a *App) GetSavedQueries(connectionID string) ([]models.SavedQuery, string) { if a.querySvc == nil { return []models.SavedQuery{}, "Service not initialized" } queries, err := a.querySvc.GetSavedQueries(a.ctx, connectionID) if err != nil { config.GetLogger().Error("failed to get saved queries", zap.Error(err)) return []models.SavedQuery{}, err.Error() } return queries, "" } // CreateSavedQuery creates a new saved query func (a *App) CreateSavedQuery(req models.CreateSavedQueryRequest) (*models.SavedQuery, string) { if a.querySvc == nil { return nil, "Service not initialized" } query, err := a.querySvc.CreateSavedQuery(a.ctx, &req) if err != nil { config.GetLogger().Error("failed to create saved query", zap.Error(err)) return nil, err.Error() } return query, "" } // UpdateSavedQuery updates a saved query func (a *App) UpdateSavedQuery(id uint, req models.UpdateSavedQueryRequest) (*models.SavedQuery, string) { if a.querySvc == nil { return nil, "Service not initialized" } query, err := a.querySvc.UpdateSavedQuery(a.ctx, id, &req) if err != nil { config.GetLogger().Error("failed to update saved query", zap.Error(err)) return nil, err.Error() } return query, "" } // DeleteSavedQuery deletes a saved query func (a *App) DeleteSavedQuery(id uint) string { if a.querySvc == nil { return "Service not initialized" } err := a.querySvc.DeleteSavedQuery(a.ctx, id) if err != nil { config.GetLogger().Error("failed to delete saved query", zap.Error(err)) return err.Error() } return "" } // StartHTTPServer starts the HTTP API server in background func (a *App) StartHTTPServer() string { if a.httpServer == nil { return "HTTP server not initialized" } go func() { port := a.config.API.Port if err := a.httpServer.Start(port); err != nil { config.GetLogger().Error("HTTP server error", zap.Error(err)) } }() return "" } // Shutdown gracefully shuts down the application func (a *App) Shutdown() { config.GetLogger().Info("shutting down application") if a.shutdownFunc != nil { a.shutdownFunc() } if a.httpServer != nil { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() a.httpServer.Shutdown(ctx) } // Close all database connections database.CloseSQLite() config.Sync() }