Export database or table to sql
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
neturl "net/url"
|
neturl "net/url"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -398,3 +399,32 @@ func GetInfo(c *gin.Context) {
|
|||||||
|
|
||||||
c.JSON(200, info)
|
c.JSON(200, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export database or table data
|
||||||
|
func DataExport(c *gin.Context) {
|
||||||
|
db := DB(c)
|
||||||
|
|
||||||
|
info, err := db.Info()
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(400, Error{err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dump := client.Dump{
|
||||||
|
Table: strings.TrimSpace(c.Request.FormValue("table")),
|
||||||
|
}
|
||||||
|
|
||||||
|
formattedInfo := info.Format()[0]
|
||||||
|
filename := formattedInfo["current_database"].(string)
|
||||||
|
if dump.Table != "" {
|
||||||
|
filename = filename + "_" + dump.Table
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment := fmt.Sprintf(`attachment; filename="%s.sql.gz"`, filename)
|
||||||
|
c.Header("Content-Disposition", attachment)
|
||||||
|
|
||||||
|
err = dump.Export(db.ConnectionString, c.Writer)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(400, Error{err.Error()})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,5 +47,6 @@ func SetupRoutes(router *gin.Engine) {
|
|||||||
api.POST("/explain", ExplainQuery)
|
api.POST("/explain", ExplainQuery)
|
||||||
api.GET("/history", GetHistory)
|
api.GET("/history", GetHistory)
|
||||||
api.GET("/bookmarks", GetBookmarks)
|
api.GET("/bookmarks", GetBookmarks)
|
||||||
|
api.GET("/export", DataExport)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
37
pkg/client/dump.go
Normal file
37
pkg/client/dump.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Dump struct {
|
||||||
|
Table string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dump) Export(url string, writer io.Writer) error {
|
||||||
|
errOutput := bytes.NewBuffer(nil)
|
||||||
|
|
||||||
|
opts := []string{
|
||||||
|
"--no-owner", // skip restoration of object ownership in plain-text format
|
||||||
|
"--clean", // clean (drop) database objects before recreating
|
||||||
|
"--compress", "6", // compression level for compressed formats
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.Table != "" {
|
||||||
|
opts = append(opts, []string{"--table", d.Table}...)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = append(opts, url)
|
||||||
|
|
||||||
|
cmd := exec.Command("pg_dump", opts...)
|
||||||
|
cmd.Stdout = writer
|
||||||
|
cmd.Stderr = errOutput
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
return fmt.Errorf("error: %s. output: %s", err.Error(), errOutput.Bytes())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -239,6 +239,8 @@
|
|||||||
<li><a href="#" data-action="export" data-format="csv">Export to CSV</a></li>
|
<li><a href="#" data-action="export" data-format="csv">Export to CSV</a></li>
|
||||||
<li><a href="#" data-action="export" data-format="xml">Export to XML</a></li>
|
<li><a href="#" data-action="export" data-format="xml">Export to XML</a></li>
|
||||||
<li class="divider"></li>
|
<li class="divider"></li>
|
||||||
|
<li><a href="#" data-action="dump">Export SQL dump</a></li>
|
||||||
|
<li class="divider"></li>
|
||||||
<li><a href="#" data-action="truncate">Truncate Table</a></li>
|
<li><a href="#" data-action="truncate">Truncate Table</a></li>
|
||||||
<li><a href="#" data-action="delete">Delete Table</a></li>
|
<li><a href="#" data-action="delete">Delete Table</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -246,6 +248,11 @@
|
|||||||
<div id="databases_context_menu">
|
<div id="databases_context_menu">
|
||||||
<ul class="dropdown-menu" role="menu"></ul>
|
<ul class="dropdown-menu" role="menu"></ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="current_database_context_menu">
|
||||||
|
<ul class="dropdown-menu" role="menu">
|
||||||
|
<li><a href="#" data-action="export">Export SQL dump</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
<div id="results_header_menu">
|
<div id="results_header_menu">
|
||||||
<ul class="dropdown-menu" role="menu">
|
<ul class="dropdown-menu" role="menu">
|
||||||
<li><a href="#" data-action="unique_values" data-counts="false">Unique Values</a></li>
|
<li><a href="#" data-action="unique_values" data-counts="false">Unique Values</a></li>
|
||||||
|
|||||||
@@ -219,6 +219,11 @@ function performTableAction(table, action, el) {
|
|||||||
var win = window.open(url, "_blank");
|
var win = window.open(url, "_blank");
|
||||||
win.focus();
|
win.focus();
|
||||||
break;
|
break;
|
||||||
|
case "dump":
|
||||||
|
var url = window.location.href.split("#")[0] + "api/export?table=" + table + "&_session_id=" + getSessionId();
|
||||||
|
var win = window.open(url, "_blank");
|
||||||
|
win.focus();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -809,8 +814,26 @@ function bindTableHeaderMenu() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bindCurrentDatabaseMenu() {
|
||||||
|
$("#current_database").contextmenu({
|
||||||
|
target: "#current_database_context_menu",
|
||||||
|
onItem: function(context, e) {
|
||||||
|
var menuItem = $(e.target);
|
||||||
|
|
||||||
|
switch(menuItem.data("action")) {
|
||||||
|
case "export":
|
||||||
|
var url = window.location.href.split("#")[0] + "api/export?_session_id=" + getSessionId();
|
||||||
|
var win = window.open(url, "_blank");
|
||||||
|
win.focus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function bindContextMenus() {
|
function bindContextMenus() {
|
||||||
bindTableHeaderMenu();
|
bindTableHeaderMenu();
|
||||||
|
bindCurrentDatabaseMenu();
|
||||||
|
|
||||||
$(".schema-group ul").each(function(id, el) {
|
$(".schema-group ul").each(function(id, el) {
|
||||||
$(el).contextmenu({
|
$(el).contextmenu({
|
||||||
@@ -825,7 +848,7 @@ function bindContextMenus() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#current_database").contextmenu({
|
$(".tables-list .title").contextmenu({
|
||||||
target: "#databases_context_menu",
|
target: "#databases_context_menu",
|
||||||
onItem: function(context, e) {
|
onItem: function(context, e) {
|
||||||
var name = $(e.target).text();
|
var name = $(e.target).text();
|
||||||
@@ -1037,7 +1060,7 @@ $(document).ready(function() {
|
|||||||
resp.forEach(function(name) {
|
resp.forEach(function(name) {
|
||||||
$("<li><a href='#'>" + name + "</a></li>").appendTo("#databases_context_menu > ul");
|
$("<li><a href='#'>" + name + "</a></li>").appendTo("#databases_context_menu > ul");
|
||||||
});
|
});
|
||||||
$("#current_database").triggerHandler("contextmenu");
|
$(".tables-list .title").triggerHandler("contextmenu");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user