Restructure
This commit is contained in:
72
api.go
Normal file
72
api.go
Normal file
@@ -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)
|
||||||
|
}
|
||||||
109
client.go
Normal file
109
client.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
181
main.go
181
main.go
@@ -1,40 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/jessevdk/go-flags"
|
"github.com/jessevdk/go-flags"
|
||||||
"github.com/jmoiron/sqlx"
|
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"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 {
|
var options struct {
|
||||||
Url string `long:"url" description:"Database connection string"`
|
Url string `long:"url" description:"Database connection string"`
|
||||||
Host string `short:"h" long:"host" description:"Server hostname or IP" default:"localhost"`
|
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"`
|
Static string `short:"s" description:"Path to static assets" default:"./static"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (res *Result) Format() []map[string]interface{} {
|
var dbClient *Client
|
||||||
var items []map[string]interface{}
|
var history []string
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func getConnectionString() string {
|
func getConnectionString() string {
|
||||||
if options.Url != "" {
|
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() {
|
func initClient() {
|
||||||
client, err := NewClient()
|
client, err := NewClient()
|
||||||
|
|
||||||
@@ -232,6 +61,7 @@ func initOptions() {
|
|||||||
func main() {
|
func main() {
|
||||||
initOptions()
|
initOptions()
|
||||||
initClient()
|
initClient()
|
||||||
|
|
||||||
defer dbClient.db.Close()
|
defer dbClient.db.Close()
|
||||||
|
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
@@ -239,10 +69,9 @@ func main() {
|
|||||||
router.GET("/info", API_Info)
|
router.GET("/info", API_Info)
|
||||||
router.GET("/tables", API_GetTables)
|
router.GET("/tables", API_GetTables)
|
||||||
router.GET("/tables/:name", API_GetTable)
|
router.GET("/tables/:name", API_GetTable)
|
||||||
router.GET("/select", API_RunQuery)
|
router.GET("/query", API_RunQuery)
|
||||||
router.POST("/select", API_RunQuery)
|
router.POST("/query", API_RunQuery)
|
||||||
router.GET("/history", API_History)
|
router.GET("/history", API_History)
|
||||||
|
|
||||||
router.Static("/app", options.Static)
|
router.Static("/app", options.Static)
|
||||||
|
|
||||||
fmt.Println("Starting server at 0.0.0.0:8080")
|
fmt.Println("Starting server at 0.0.0.0:8080")
|
||||||
|
|||||||
Reference in New Issue
Block a user