From 40cae0ac1c9988064fe45c018c6634eb6d739cd9 Mon Sep 17 00:00:00 2001 From: Dan Sosedoff Date: Fri, 10 Oct 2014 17:14:17 -0500 Subject: [PATCH] Restructure --- api.go | 72 ++++++++++++++++++++++ client.go | 109 ++++++++++++++++++++++++++++++++ main.go | 181 ++---------------------------------------------------- 3 files changed, 186 insertions(+), 176 deletions(-) create mode 100644 api.go create mode 100644 client.go diff --git a/api.go b/api.go new file mode 100644 index 0000000..408daa9 --- /dev/null +++ b/api.go @@ -0,0 +1,72 @@ +package main + +import ( + "errors" + "fmt" + "github.com/gin-gonic/gin" + "strings" +) + +type Error struct { + Message string `json:"error"` +} + +func API_RunQuery(c *gin.Context) { + query := strings.TrimSpace(c.Request.FormValue("query")) + + if query == "" { + c.JSON(400, errors.New("Query parameter is missing")) + return + } + + history = append(history, query) + API_HandleQuery(query, c) +} + +func API_GetTables(c *gin.Context) { + names, err := dbClient.Tables() + + if err != nil { + c.JSON(400, NewError(err)) + return + } + + c.JSON(200, names) +} + +func API_GetTable(c *gin.Context) { + res, err := dbClient.Query(fmt.Sprintf(SQL_TABLE_SCHEMA, c.Params.ByName("name"))) + + if err != nil { + c.JSON(400, NewError(err)) + return + } + + c.JSON(200, res.Format()) +} + +func API_History(c *gin.Context) { + c.JSON(200, history) +} + +func API_Info(c *gin.Context) { + res, err := dbClient.Query(SQL_INFO) + + if err != nil { + c.JSON(400, NewError(err)) + return + } + + c.JSON(200, res.Format()[0]) +} + +func API_HandleQuery(query string, c *gin.Context) { + result, err := dbClient.Query(query) + + if err != nil { + c.JSON(400, NewError(err)) + return + } + + c.JSON(200, result) +} diff --git a/client.go b/client.go new file mode 100644 index 0000000..0983323 --- /dev/null +++ b/client.go @@ -0,0 +1,109 @@ +package main + +import ( + "github.com/jmoiron/sqlx" + "reflect" +) + +const ( + SQL_INFO = "SELECT version(), user, current_database(), inet_client_addr(), inet_client_port(), inet_server_addr(), inet_server_port()" + SQL_TABLES = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_schema,table_name;" + SQL_TABLE_SCHEMA = "SELECT column_name, data_type, is_nullable, character_maximum_length, character_set_catalog, column_default FROM information_schema.columns where table_name = '%s';" +) + +type Client struct { + db *sqlx.DB +} + +type Result struct { + Columns []string `json:"columns"` + Rows [][]interface{} `json:"rows"` +} + +func NewError(err error) Error { + return Error{err.Error()} +} + +func NewClient() (*Client, error) { + db, err := sqlx.Open("postgres", getConnectionString()) + + if err != nil { + return nil, err + } + + return &Client{db: db}, nil +} + +func (client *Client) Tables() ([]string, error) { + res, err := client.Query(SQL_TABLES) + + if err != nil { + return nil, err + } + + var tables []string + + for _, row := range res.Rows { + tables = append(tables, row[0].(string)) + } + + return tables, nil +} + +func (client *Client) Query(query string) (*Result, error) { + rows, err := client.db.Queryx(query) + + if err != nil { + return nil, err + } + + defer rows.Close() + + cols, err := rows.Columns() + + if err != nil { + return nil, err + } + + result := Result{ + Columns: cols, + } + + for rows.Next() { + obj, err := rows.SliceScan() + + for i, item := range obj { + if item == nil { + obj[i] = nil + } else { + t := reflect.TypeOf(item).Kind().String() + + if t == "slice" { + obj[i] = string(item.([]byte)) + } + } + } + + if err == nil { + result.Rows = append(result.Rows, obj) + } + } + + return &result, nil +} + +func (res *Result) Format() []map[string]interface{} { + var items []map[string]interface{} + + for _, row := range res.Rows { + item := make(map[string]interface{}) + + for i, c := range res.Columns { + item[c] = row[i] + } + + items = append(items, item) + } + + return items +} diff --git a/main.go b/main.go index 005744a..5e769ef 100644 --- a/main.go +++ b/main.go @@ -1,40 +1,14 @@ package main import ( - "errors" "fmt" "github.com/gin-gonic/gin" "github.com/jessevdk/go-flags" - "github.com/jmoiron/sqlx" _ "github.com/lib/pq" "log" "os" - "reflect" - "strings" ) -const ( - SQL_INFO = "SELECT version(), user, current_database(), inet_client_addr(), inet_client_port(), inet_server_addr(), inet_server_port()" - SQL_TABLES = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' ORDER BY table_schema,table_name;" - SQL_TABLE_SCHEMA = "SELECT column_name, data_type, is_nullable, character_maximum_length, character_set_catalog, column_default FROM information_schema.columns where table_name = '%s';" -) - -type Client struct { - db *sqlx.DB -} - -type Result struct { - Columns []string `json:"columns"` - Rows [][]interface{} `json:"rows"` -} - -type Error struct { - Message string `json:"error"` -} - -var dbClient *Client -var history []string - var options struct { Url string `long:"url" description:"Database connection string"` Host string `short:"h" long:"host" description:"Server hostname or IP" default:"localhost"` @@ -45,21 +19,8 @@ var options struct { Static string `short:"s" description:"Path to static assets" default:"./static"` } -func (res *Result) Format() []map[string]interface{} { - var items []map[string]interface{} - - for _, row := range res.Rows { - item := make(map[string]interface{}) - - for i, c := range res.Columns { - item[c] = row[i] - } - - items = append(items, item) - } - - return items -} +var dbClient *Client +var history []string func getConnectionString() string { if options.Url != "" { @@ -73,138 +34,6 @@ func getConnectionString() string { ) } -func NewClient() (*Client, error) { - db, err := sqlx.Open("postgres", getConnectionString()) - - if err != nil { - return nil, err - } - - return &Client{db: db}, nil -} - -func NewError(err error) Error { - return Error{err.Error()} -} - -func (client *Client) Tables() ([]string, error) { - res, err := client.Query(SQL_TABLES) - - if err != nil { - return nil, err - } - - var tables []string - - for _, row := range res.Rows { - tables = append(tables, row[0].(string)) - } - - return tables, nil -} - -func (client *Client) Query(query string) (*Result, error) { - rows, err := client.db.Queryx(query) - - if err != nil { - return nil, err - } - - defer rows.Close() - - cols, err := rows.Columns() - - if err != nil { - return nil, err - } - - result := Result{ - Columns: cols, - } - - for rows.Next() { - obj, err := rows.SliceScan() - - for i, item := range obj { - if item == nil { - obj[i] = nil - } else { - t := reflect.TypeOf(item).Kind().String() - - if t == "slice" { - obj[i] = string(item.([]byte)) - } - } - } - - if err == nil { - result.Rows = append(result.Rows, obj) - } - } - - return &result, nil -} - -func API_RunQuery(c *gin.Context) { - query := strings.TrimSpace(c.Request.FormValue("query")) - - if query == "" { - c.JSON(400, errors.New("Query parameter is missing")) - return - } - - history = append(history, query) - API_HandleQuery(query, c) -} - -func API_GetTables(c *gin.Context) { - names, err := dbClient.Tables() - - if err != nil { - c.JSON(400, NewError(err)) - return - } - - c.JSON(200, names) -} - -func API_GetTable(c *gin.Context) { - res, err := dbClient.Query(fmt.Sprintf(SQL_TABLE_SCHEMA, c.Params.ByName("name"))) - - if err != nil { - c.JSON(400, NewError(err)) - return - } - - c.JSON(200, res.Format()) -} - -func API_History(c *gin.Context) { - c.JSON(200, history) -} - -func API_Info(c *gin.Context) { - res, err := dbClient.Query(SQL_INFO) - - if err != nil { - c.JSON(400, NewError(err)) - return - } - - c.JSON(200, res.Format()[0]) -} - -func API_HandleQuery(query string, c *gin.Context) { - result, err := dbClient.Query(query) - - if err != nil { - c.JSON(400, NewError(err)) - return - } - - c.JSON(200, result) -} - func initClient() { client, err := NewClient() @@ -232,6 +61,7 @@ func initOptions() { func main() { initOptions() initClient() + defer dbClient.db.Close() router := gin.Default() @@ -239,10 +69,9 @@ func main() { router.GET("/info", API_Info) router.GET("/tables", API_GetTables) router.GET("/tables/:name", API_GetTable) - router.GET("/select", API_RunQuery) - router.POST("/select", API_RunQuery) + router.GET("/query", API_RunQuery) + router.POST("/query", API_RunQuery) router.GET("/history", API_History) - router.Static("/app", options.Static) fmt.Println("Starting server at 0.0.0.0:8080")