Code formatting and cleanup (#442)
* Formatting, extract error messages * More refactor * Move errors to a separate file * Add missing file * Misc
This commit is contained in:
parent
c4db1973c4
commit
7a6450091a
119
pkg/api/api.go
119
pkg/api/api.go
@ -2,7 +2,6 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
neturl "net/url"
|
neturl "net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -31,11 +30,11 @@ var (
|
|||||||
func DB(c *gin.Context) *client.Client {
|
func DB(c *gin.Context) *client.Client {
|
||||||
if command.Opts.Sessions {
|
if command.Opts.Sessions {
|
||||||
return DbSessions[getSessionId(c.Request)]
|
return DbSessions[getSessionId(c.Request)]
|
||||||
} else {
|
}
|
||||||
return DbClient
|
return DbClient
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// setClient sets the database client connection for the sessions
|
||||||
func setClient(c *gin.Context, newClient *client.Client) error {
|
func setClient(c *gin.Context, newClient *client.Client) error {
|
||||||
currentClient := DB(c)
|
currentClient := DB(c)
|
||||||
if currentClient != nil {
|
if currentClient != nil {
|
||||||
@ -47,23 +46,26 @@ func setClient(c *gin.Context, newClient *client.Client) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionId := getSessionId(c.Request)
|
sid := getSessionId(c.Request)
|
||||||
if sessionId == "" {
|
if sid == "" {
|
||||||
return errors.New("Session ID is required")
|
return errSessionRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
DbSessions[sessionId] = newClient
|
DbSessions[sid] = newClient
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHome renderes the home page
|
||||||
func GetHome(c *gin.Context) {
|
func GetHome(c *gin.Context) {
|
||||||
serveStaticAsset("/index.html", c)
|
serveStaticAsset("/index.html", c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAsset renders the requested static asset
|
||||||
func GetAsset(c *gin.Context) {
|
func GetAsset(c *gin.Context) {
|
||||||
serveStaticAsset(c.Params.ByName("path"), c)
|
serveStaticAsset(c.Params.ByName("path"), c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSessions renders the number of active sessions
|
||||||
func GetSessions(c *gin.Context) {
|
func GetSessions(c *gin.Context) {
|
||||||
// In debug mode endpoint will return a lot of sensitive information
|
// In debug mode endpoint will return a lot of sensitive information
|
||||||
// like full database connection string and all query history.
|
// like full database connection string and all query history.
|
||||||
@ -74,6 +76,7 @@ func GetSessions(c *gin.Context) {
|
|||||||
successResponse(c, gin.H{"sessions": len(DbSessions)})
|
successResponse(c, gin.H{"sessions": len(DbSessions)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConnectWithBackend creates a new connection based on backend resource
|
||||||
func ConnectWithBackend(c *gin.Context) {
|
func ConnectWithBackend(c *gin.Context) {
|
||||||
// Setup a new backend client
|
// Setup a new backend client
|
||||||
backend := Backend{
|
backend := Backend{
|
||||||
@ -90,12 +93,12 @@ func ConnectWithBackend(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make the new session
|
// Make the new session
|
||||||
sessionId, err := securerandom.Uuid()
|
sid, err := securerandom.Uuid()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
badRequest(c, err)
|
badRequest(c, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Request.Header.Add("x-session-id", sessionId)
|
c.Request.Header.Add("x-session-id", sid)
|
||||||
|
|
||||||
// Connect to the database
|
// Connect to the database
|
||||||
cl, err := client.NewFromUrl(cred.DatabaseURL, nil)
|
cl, err := client.NewFromUrl(cred.DatabaseURL, nil)
|
||||||
@ -116,12 +119,14 @@ func ConnectWithBackend(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Redirect(301, fmt.Sprintf("/%s?session=%s", command.Opts.Prefix, sessionId))
|
redirectURI := fmt.Sprintf("/%s?session=%s", command.Opts.Prefix, sid)
|
||||||
|
c.Redirect(301, redirectURI)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Connect creates a new client connection
|
||||||
func Connect(c *gin.Context) {
|
func Connect(c *gin.Context) {
|
||||||
if command.Opts.LockSession {
|
if command.Opts.LockSession {
|
||||||
badRequest(c, "Session is locked")
|
badRequest(c, errSessionLocked)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +134,7 @@ func Connect(c *gin.Context) {
|
|||||||
url := c.Request.FormValue("url")
|
url := c.Request.FormValue("url")
|
||||||
|
|
||||||
if url == "" {
|
if url == "" {
|
||||||
badRequest(c, "Url parameter is required")
|
badRequest(c, errURLRequired)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,9 +175,10 @@ func Connect(c *gin.Context) {
|
|||||||
successResponse(c, info.Format()[0])
|
successResponse(c, info.Format()[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SwitchDb perform database switch for the client connection
|
||||||
func SwitchDb(c *gin.Context) {
|
func SwitchDb(c *gin.Context) {
|
||||||
if command.Opts.LockSession {
|
if command.Opts.LockSession {
|
||||||
badRequest(c, "Session is locked")
|
badRequest(c, errSessionLocked)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,31 +187,30 @@ func SwitchDb(c *gin.Context) {
|
|||||||
name = c.Request.FormValue("db")
|
name = c.Request.FormValue("db")
|
||||||
}
|
}
|
||||||
if name == "" {
|
if name == "" {
|
||||||
badRequest(c, "Database name is not provided")
|
badRequest(c, errDatabaseNameRequired)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn := DB(c)
|
conn := DB(c)
|
||||||
if conn == nil {
|
if conn == nil {
|
||||||
badRequest(c, "Not connected")
|
badRequest(c, errNotConnected)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not allow switching databases for connections from third-party backends
|
// Do not allow switching databases for connections from third-party backends
|
||||||
if conn.External {
|
if conn.External {
|
||||||
badRequest(c, "Session is locked")
|
badRequest(c, errSessionLocked)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
currentUrl, err := neturl.Parse(conn.ConnectionString)
|
currentURL, err := neturl.Parse(conn.ConnectionString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
badRequest(c, "Unable to parse current connection string")
|
badRequest(c, errInvalidConnString)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
currentURL.Path = name
|
||||||
|
|
||||||
currentUrl.Path = name
|
cl, err := client.NewFromUrl(currentURL.String(), nil)
|
||||||
|
|
||||||
cl, err := client.NewFromUrl(currentUrl.String(), nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
badRequest(c, err)
|
badRequest(c, err)
|
||||||
return
|
return
|
||||||
@ -232,16 +237,16 @@ func SwitchDb(c *gin.Context) {
|
|||||||
successResponse(c, info.Format()[0])
|
successResponse(c, info.Format()[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disconnect closes the current database connection
|
||||||
func Disconnect(c *gin.Context) {
|
func Disconnect(c *gin.Context) {
|
||||||
if command.Opts.LockSession {
|
if command.Opts.LockSession {
|
||||||
badRequest(c, "Session is locked")
|
badRequest(c, errSessionLocked)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn := DB(c)
|
conn := DB(c)
|
||||||
|
|
||||||
if conn == nil {
|
if conn == nil {
|
||||||
badRequest(c, "Not connected")
|
badRequest(c, errNotConnected)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,10 +259,35 @@ func Disconnect(c *gin.Context) {
|
|||||||
successResponse(c, gin.H{"success": true})
|
successResponse(c, gin.H{"success": true})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RunQuery executes the query
|
||||||
|
func RunQuery(c *gin.Context) {
|
||||||
|
query := cleanQuery(c.Request.FormValue("query"))
|
||||||
|
|
||||||
|
if query == "" {
|
||||||
|
badRequest(c, errQueryRequired)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleQuery(query, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExplainQuery renders query analyze profile
|
||||||
|
func ExplainQuery(c *gin.Context) {
|
||||||
|
query := cleanQuery(c.Request.FormValue("query"))
|
||||||
|
|
||||||
|
if query == "" {
|
||||||
|
badRequest(c, errQueryRequired)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleQuery(fmt.Sprintf("EXPLAIN ANALYZE %s", query), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDatabases renders a list of all databases on the server
|
||||||
func GetDatabases(c *gin.Context) {
|
func GetDatabases(c *gin.Context) {
|
||||||
conn := DB(c)
|
conn := DB(c)
|
||||||
if conn.External {
|
if conn.External {
|
||||||
errorResponse(c, 403, "Not permitted")
|
errorResponse(c, 403, errNotPermitted)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,6 +295,7 @@ func GetDatabases(c *gin.Context) {
|
|||||||
serveResult(c, names, err)
|
serveResult(c, names, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetObjects renders a list of database objects
|
||||||
func GetObjects(c *gin.Context) {
|
func GetObjects(c *gin.Context) {
|
||||||
result, err := DB(c).Objects()
|
result, err := DB(c).Objects()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -274,33 +305,13 @@ func GetObjects(c *gin.Context) {
|
|||||||
successResponse(c, client.ObjectsFromResult(result))
|
successResponse(c, client.ObjectsFromResult(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunQuery(c *gin.Context) {
|
// GetSchemas renders list of available schemas
|
||||||
query := cleanQuery(c.Request.FormValue("query"))
|
|
||||||
|
|
||||||
if query == "" {
|
|
||||||
badRequest(c, "Query parameter is missing")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleQuery(query, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExplainQuery(c *gin.Context) {
|
|
||||||
query := cleanQuery(c.Request.FormValue("query"))
|
|
||||||
|
|
||||||
if query == "" {
|
|
||||||
badRequest(c, "Query parameter is missing")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleQuery(fmt.Sprintf("EXPLAIN ANALYZE %s", query), c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSchemas(c *gin.Context) {
|
func GetSchemas(c *gin.Context) {
|
||||||
res, err := DB(c).Schemas()
|
res, err := DB(c).Schemas()
|
||||||
serveResult(c, res, err)
|
serveResult(c, res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTable renders table information
|
||||||
func GetTable(c *gin.Context) {
|
func GetTable(c *gin.Context) {
|
||||||
var res *client.Result
|
var res *client.Result
|
||||||
var err error
|
var err error
|
||||||
@ -314,6 +325,7 @@ func GetTable(c *gin.Context) {
|
|||||||
serveResult(c, res, err)
|
serveResult(c, res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTableRows renders table rows
|
||||||
func GetTableRows(c *gin.Context) {
|
func GetTableRows(c *gin.Context) {
|
||||||
offset, err := parseIntFormValue(c, "offset", 0)
|
offset, err := parseIntFormValue(c, "offset", 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -366,6 +378,7 @@ func GetTableRows(c *gin.Context) {
|
|||||||
serveResult(c, res, err)
|
serveResult(c, res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTableInfo renders a selected table information
|
||||||
func GetTableInfo(c *gin.Context) {
|
func GetTableInfo(c *gin.Context) {
|
||||||
res, err := DB(c).TableInfo(c.Params.ByName("table"))
|
res, err := DB(c).TableInfo(c.Params.ByName("table"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -375,10 +388,12 @@ func GetTableInfo(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHistory renders a list of recent queries
|
||||||
func GetHistory(c *gin.Context) {
|
func GetHistory(c *gin.Context) {
|
||||||
successResponse(c, DB(c).History)
|
successResponse(c, DB(c).History)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetConnectionInfo renders information about current connection
|
||||||
func GetConnectionInfo(c *gin.Context) {
|
func GetConnectionInfo(c *gin.Context) {
|
||||||
res, err := DB(c).Info()
|
res, err := DB(c).Info()
|
||||||
|
|
||||||
@ -393,21 +408,25 @@ func GetConnectionInfo(c *gin.Context) {
|
|||||||
successResponse(c, info)
|
successResponse(c, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetActivity renders a list of running queries
|
||||||
func GetActivity(c *gin.Context) {
|
func GetActivity(c *gin.Context) {
|
||||||
res, err := DB(c).Activity()
|
res, err := DB(c).Activity()
|
||||||
serveResult(c, res, err)
|
serveResult(c, res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTableIndexes renders a list of database table indexes
|
||||||
func GetTableIndexes(c *gin.Context) {
|
func GetTableIndexes(c *gin.Context) {
|
||||||
res, err := DB(c).TableIndexes(c.Params.ByName("table"))
|
res, err := DB(c).TableIndexes(c.Params.ByName("table"))
|
||||||
serveResult(c, res, err)
|
serveResult(c, res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTableConstraints renders a list of database constraints
|
||||||
func GetTableConstraints(c *gin.Context) {
|
func GetTableConstraints(c *gin.Context) {
|
||||||
res, err := DB(c).TableConstraints(c.Params.ByName("table"))
|
res, err := DB(c).TableConstraints(c.Params.ByName("table"))
|
||||||
serveResult(c, res, err)
|
serveResult(c, res, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HandleQuery runs the database query
|
||||||
func HandleQuery(query string, c *gin.Context) {
|
func HandleQuery(query string, c *gin.Context) {
|
||||||
rawQuery, err := base64.StdEncoding.DecodeString(desanitize64(query))
|
rawQuery, err := base64.StdEncoding.DecodeString(desanitize64(query))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -443,11 +462,13 @@ func HandleQuery(query string, c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBookmarks renders the list of available bookmarks
|
||||||
func GetBookmarks(c *gin.Context) {
|
func GetBookmarks(c *gin.Context) {
|
||||||
bookmarks, err := bookmarks.ReadAll(bookmarks.Path(command.Opts.BookmarksDir))
|
bookmarks, err := bookmarks.ReadAll(bookmarks.Path(command.Opts.BookmarksDir))
|
||||||
serveResult(c, bookmarks, err)
|
serveResult(c, bookmarks, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetInfo renders the pgweb system information
|
||||||
func GetInfo(c *gin.Context) {
|
func GetInfo(c *gin.Context) {
|
||||||
successResponse(c, gin.H{
|
successResponse(c, gin.H{
|
||||||
"version": command.Version,
|
"version": command.Version,
|
||||||
@ -456,7 +477,7 @@ func GetInfo(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export database or table data
|
// DataExport performs database table export
|
||||||
func DataExport(c *gin.Context) {
|
func DataExport(c *gin.Context) {
|
||||||
db := DB(c)
|
db := DB(c)
|
||||||
|
|
||||||
@ -473,7 +494,7 @@ func DataExport(c *gin.Context) {
|
|||||||
// If pg_dump is not available the following code will not show an error in browser.
|
// If pg_dump is not available the following code will not show an error in browser.
|
||||||
// This is due to the headers being written first.
|
// This is due to the headers being written first.
|
||||||
if !dump.CanExport() {
|
if !dump.CanExport() {
|
||||||
badRequest(c, "pg_dump is not found")
|
badRequest(c, errPgDumpNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ func (be Backend) FetchCredential(resource string, c *gin.Context) (*BackendCred
|
|||||||
log.Println("Unable to fetch backend credential:", err)
|
log.Println("Unable to fetch backend credential:", err)
|
||||||
|
|
||||||
// We dont want to expose the url of the backend here, so reply with generic error
|
// We dont want to expose the url of the backend here, so reply with generic error
|
||||||
return nil, fmt.Errorf("Unable to connect to the auth backend")
|
return nil, errBackendConnectError
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ func (be Backend) FetchCredential(resource string, c *gin.Context) (*BackendCred
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if cred.DatabaseURL == "" {
|
if cred.DatabaseURL == "" {
|
||||||
return nil, fmt.Errorf("Database URL was not provided")
|
return nil, errConnStringRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
return cred, nil
|
return cred, nil
|
||||||
|
19
pkg/api/errors.go
Normal file
19
pkg/api/errors.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errNotConnected = errors.New("Not connected")
|
||||||
|
errNotPermitted = errors.New("Not permitted")
|
||||||
|
errConnStringRequired = errors.New("Connection string is required")
|
||||||
|
errInvalidConnString = errors.New("Invalid connection string")
|
||||||
|
errSessionRequired = errors.New("Session ID is required")
|
||||||
|
errSessionLocked = errors.New("Session is locked")
|
||||||
|
errURLRequired = errors.New("URL parameter is required")
|
||||||
|
errQueryRequired = errors.New("Query parameter is required")
|
||||||
|
errDatabaseNameRequired = errors.New("Database name is required")
|
||||||
|
errPgDumpNotFound = errors.New("pg_dump utility is not found")
|
||||||
|
errBackendConnectError = errors.New("Unable to connect to the auth backend")
|
||||||
|
)
|
@ -23,7 +23,7 @@ func dbCheckMiddleware() gin.HandlerFunc {
|
|||||||
// Check if session exists in single-session mode
|
// Check if session exists in single-session mode
|
||||||
if !command.Opts.Sessions {
|
if !command.Opts.Sessions {
|
||||||
if DbClient == nil {
|
if DbClient == nil {
|
||||||
badRequest(c, "Not connected")
|
badRequest(c, errNotConnected)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,16 +32,16 @@ func dbCheckMiddleware() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine session ID from the client request
|
// Determine session ID from the client request
|
||||||
sessionId := getSessionId(c.Request)
|
sid := getSessionId(c.Request)
|
||||||
if sessionId == "" {
|
if sid == "" {
|
||||||
badRequest(c, "Session ID is required")
|
badRequest(c, errSessionRequired)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the database connection handle for the session
|
// Determine the database connection handle for the session
|
||||||
conn := DbSessions[sessionId]
|
conn := DbSessions[sid]
|
||||||
if conn == nil {
|
if conn == nil {
|
||||||
badRequest(c, "Not connected")
|
badRequest(c, errNotConnected)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,16 @@ import (
|
|||||||
"github.com/sosedoff/pgweb/pkg/util"
|
"github.com/sosedoff/pgweb/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var options command.Options
|
var (
|
||||||
|
options command.Options
|
||||||
|
|
||||||
|
readonlyWarning = `
|
||||||
|
------------------------------------------------------
|
||||||
|
SECURITY WARNING: You are running pgweb in read-only mode.
|
||||||
|
This mode is designed for environments where users could potentially delete / change data.
|
||||||
|
For proper read-only access please follow postgresql role management documentation.
|
||||||
|
------------------------------------------------------`
|
||||||
|
)
|
||||||
|
|
||||||
func exitWithMessage(message string) {
|
func exitWithMessage(message string) {
|
||||||
fmt.Println("Error:", message)
|
fmt.Println("Error:", message)
|
||||||
@ -127,12 +136,7 @@ func initOptions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if options.ReadOnly {
|
if options.ReadOnly {
|
||||||
msg := `------------------------------------------------------
|
fmt.Println(readonlyWarning)
|
||||||
SECURITY WARNING: You are running pgweb in read-only mode.
|
|
||||||
This mode is designed for environments where users could potentially delete / change data.
|
|
||||||
For proper read-only access please follow postgresql role management documentation.
|
|
||||||
------------------------------------------------------`
|
|
||||||
fmt.Println(msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printVersion()
|
printVersion()
|
||||||
|
@ -22,8 +22,7 @@ type Dump struct {
|
|||||||
|
|
||||||
// CanExport returns true if database dump tool could be used without an error
|
// CanExport returns true if database dump tool could be used without an error
|
||||||
func (d *Dump) CanExport() bool {
|
func (d *Dump) CanExport() bool {
|
||||||
err := exec.Command("pg_dump", "--version").Run()
|
return exec.Command("pg_dump", "--version").Run() == nil
|
||||||
return err == nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export streams the database dump to the specified writer
|
// Export streams the database dump to the specified writer
|
||||||
|
Loading…
x
Reference in New Issue
Block a user