diff --git a/README.md b/README.md index 5bcf670..6a0453f 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ A Go library for accessing and using SQLite databases stored remotely on DBHub.i * List the columns present in a table or view, along with their details * List the branches of a database * Generate diffs between two databases, or database revisions +* Download a complete database ### Still to do * Tests for each function * Retrieve index details for a database * Return the list of available databases -* Download a complete database * Upload a complete database * Retrieve database commit history details (size, branch, commit list, whatever else is useful) * Investigate what would be needed for this to work through the Go SQL API @@ -134,5 +134,6 @@ ORDER BY table1.id; * [Retrieve column details](https://github.com/sqlitebrowser/go-dbhub/blob/master/examples/column_details/main.go) - Retrieve the details of columns in a table * [List branches](https://github.com/sqlitebrowser/go-dbhub/blob/master/examples/list_branches/main.go) - List all branches of a database * [Generate diff between two revisions](https://github.com/sqlitebrowser/go-dbhub/blob/master/examples/diff_commits/main.go) - Figure out the differences between two databases or two versions of one database +* [Download database](https://github.com/sqlitebrowser/go-dbhub/blob/master/examples/download_database/main.go) - Download the complete database file Please try it out, submits PRs to extend or fix things, and report any weirdness or bugs you encounter. :smile: diff --git a/dbhub.go b/dbhub.go index 26dd3be..ac2d787 100644 --- a/dbhub.go +++ b/dbhub.go @@ -5,6 +5,7 @@ package dbhub import ( "encoding/base64" "fmt" + "io" "net/url" com "github.com/sqlitebrowser/dbhub.io/common" @@ -45,7 +46,7 @@ func (c Connection) Branches(dbowner, dbname string) (branches map[string]com.Br // Fetch the list of branches and the default branch var response com.BranchListResponseContainer queryUrl := c.Server + "/v1/branches" - err = sendRequest(queryUrl, data, &response) + err = sendRequestJSON(queryUrl, data, &response) // Extract information for return values branches = response.Entries @@ -61,7 +62,7 @@ func (c Connection) Columns(dbOwner, dbName string, ident Identifier, table stri // Fetch the list of columns queryUrl := c.Server + "/v1/columns" - err = sendRequest(queryUrl, data, &columns) + err = sendRequestJSON(queryUrl, data, &columns) return } @@ -109,7 +110,21 @@ func (c Connection) Diff(dbOwnerA, dbNameA string, identA Identifier, dbOwnerB, // Fetch the diffs queryUrl := c.Server + "/v1/diff" - err = sendRequest(queryUrl, data, &diffs) + err = sendRequestJSON(queryUrl, data, &diffs) + return +} + +// Download returns the database file +func (c Connection) Download(dbOwner, dbName string, ident Identifier) (db io.ReadCloser, err error) { + // Prepare the API parameters + data := c.PrepareVals(dbOwner, dbName, ident) + + // Fetch the database file + queryUrl := c.Server + "/v1/download" + db, err = sendRequest(queryUrl, data) + if err != nil { + return + } return } @@ -120,7 +135,7 @@ func (c Connection) Indexes(dbOwner, dbName string, ident Identifier) (idx map[s // Fetch the list of indexes queryUrl := c.Server + "/v1/indexes" - err = sendRequest(queryUrl, data, &idx) + err = sendRequestJSON(queryUrl, data, &idx) return } @@ -158,7 +173,7 @@ func (c Connection) Query(dbOwner, dbName string, ident Identifier, blobBase64 b // Run the query on the remote database var returnedData []com.DataRow queryUrl := c.Server + "/v1/query" - err = sendRequest(queryUrl, data, &returnedData) + err = sendRequestJSON(queryUrl, data, &returnedData) if err != nil { return } @@ -204,7 +219,7 @@ func (c Connection) Tables(dbOwner, dbName string, ident Identifier) (tbl []stri // Fetch the list of tables queryUrl := c.Server + "/v1/tables" - err = sendRequest(queryUrl, data, &tbl) + err = sendRequestJSON(queryUrl, data, &tbl) return } @@ -215,6 +230,6 @@ func (c Connection) Views(dbOwner, dbName string, ident Identifier) (views []str // Fetch the list of views queryUrl := c.Server + "/v1/views" - err = sendRequest(queryUrl, data, &views) + err = sendRequestJSON(queryUrl, data, &views) return } diff --git a/examples/download_database/main.go b/examples/download_database/main.go new file mode 100644 index 0000000..a7975af --- /dev/null +++ b/examples/download_database/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "fmt" + "io/ioutil" + "log" + + "github.com/sqlitebrowser/go-dbhub" +) + +func main() { + // Create a new DBHub.io API object + db, err := dbhub.New("YOUR_API_KEY_HERE") + if err != nil { + log.Fatal(err) + } + + // Retrieve the remote database file + dbName := "Join Testing.sqlite" + dbStream, err := db.Download("justinclift", dbName, dbhub.Identifier{}) + if err != nil { + log.Fatal(err) + } + + // Save the database file in the current directory + buf, err := ioutil.ReadAll(dbStream) + if err != nil { + log.Fatal(err) + } + err = ioutil.WriteFile(dbName, buf, 0644) + if err != nil { + log.Fatal(err) + } + fmt.Printf("Saved database file as '%s'\n", dbName) +} diff --git a/http.go b/http.go index c5ee962..462d092 100644 --- a/http.go +++ b/http.go @@ -3,14 +3,32 @@ package dbhub import ( "encoding/json" "fmt" + "io" "net/http" "net/url" "strings" ) -// sendRequest sends the query to the server. It exists because http.PostForm() doesn't seem to have a way -// to change header values. -func sendRequest(queryUrl string, data url.Values, returnStructure interface{}) (err error) { +// sendRequestJSON sends a request to DBHub.io, formatting the returned result as JSON +func sendRequestJSON(queryUrl string, data url.Values, returnStructure interface{}) (err error) { + // Send the request + var body io.ReadCloser + body, err = sendRequest(queryUrl, data) + if err != nil { + return + } + + // Unmarshall the JSON response into the structure provided by the caller + err = json.NewDecoder(body).Decode(returnStructure) + if err != nil { + return + } + return +} + +// sendRequest sends a request to DBHub.io. It exists because http.PostForm() doesn't seem to have a way of changing +// header values. +func sendRequest(queryUrl string, data url.Values) (body io.ReadCloser, err error) { var req *http.Request var resp *http.Response var client http.Client @@ -35,10 +53,7 @@ func sendRequest(queryUrl string, data url.Values, returnStructure interface{}) return } - // Unmarshall the JSON response into the structure provided by the caller - err = json.NewDecoder(resp.Body).Decode(returnStructure) - if err != nil { - return - } + // Return the response body + body = resp.Body return }