Skip to content
This repository was archived by the owner on Mar 4, 2025. It is now read-only.

Commit cc22bef

Browse files
committed
api: add function to retrieve column info for a table or view
This is called using the path "/v1/columns" on the API server.
1 parent efa86a0 commit cc22bef

File tree

4 files changed

+106
-3
lines changed

4 files changed

+106
-3
lines changed

api/handlers.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,67 @@ import (
1010
com "github.com/sqlitebrowser/dbhub.io/common"
1111
)
1212

13+
// columnsHandler returns the list of columns present in a table or view
14+
// This can be run from the command line using curl, like this:
15+
// $ curl -F apikey="YOUR_API_KEY_HERE" -F dbowner="justinclift" -F dbname="Join Testing.sqlite" https://api.dbhub.io/v1/columns
16+
// * "apikey" is one of your API keys. These can be generated from your Settings page once logged in
17+
// * "dbowner" is the owner of the database
18+
// * "dbname" is the name of the database
19+
// * "table" is the name of the table or view
20+
func columnsHandler(w http.ResponseWriter, r *http.Request) {
21+
// Do auth check, grab request info, open the database
22+
sdb, err, httpStatus := collectInfo(w, r)
23+
if err != nil {
24+
jsonErr(w, err.Error(), httpStatus)
25+
return
26+
}
27+
defer sdb.Close()
28+
29+
// Extract the table name
30+
table, err := com.GetFormTable(r, false)
31+
if err != nil {
32+
jsonErr(w, err.Error(), http.StatusInternalServerError)
33+
return
34+
}
35+
36+
// Make sure a table name was provided
37+
if table == "" {
38+
jsonErr(w, "Missing table name", http.StatusBadRequest)
39+
return
40+
}
41+
42+
// Retrieve the list of columns for the table
43+
cols, err := sdb.Columns("", table)
44+
if err != nil {
45+
jsonErr(w, err.Error(), http.StatusInternalServerError)
46+
return
47+
}
48+
49+
// Transfer the column info into our own structure, for better json formatting
50+
var jsonCols []com.APIJSONColumn
51+
for _, j := range cols {
52+
jsonCols = append(jsonCols, com.APIJSONColumn{
53+
Cid: j.Cid,
54+
Name: j.Name,
55+
DataType: j.DataType,
56+
NotNull: j.NotNull,
57+
DfltValue: j.DfltValue,
58+
Pk: j.Pk,
59+
Autoinc: j.Autoinc,
60+
CollSeq: j.CollSeq,
61+
})
62+
}
63+
64+
// Return the results
65+
jsonData, err := json.Marshal(jsonCols)
66+
if err != nil {
67+
log.Printf("Error when JSON marshalling returned data in columnsHandler(): %v\n", err)
68+
jsonErr(w, err.Error(), http.StatusInternalServerError)
69+
return
70+
}
71+
fmt.Fprintf(w, string(jsonData))
72+
}
73+
1374
// diffHandler generates a diff between two databases or two versions of a database
1475
// This can be run from the command line using curl, like this:
1576
// $ curl -F apikey="YOUR_API_KEY_HERE" -F dbowner_a="justinclift" -F dbname_a="Join Testing.sqlite" -F commit_a="ea12..." -F commit_b="5a7c..." https://api.dbhub.io/v1/diff

api/main.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,12 @@ func main() {
7878

7979
// Our pages
8080
http.Handle("/", gz.GzipHandler(handleWrapper(rootHandler)))
81+
http.Handle("/v1/columns", gz.GzipHandler(handleWrapper(columnsHandler)))
82+
http.Handle("/v1/diff", gz.GzipHandler(handleWrapper(diffHandler)))
8183
http.Handle("/v1/indexes", gz.GzipHandler(handleWrapper(indexesHandler)))
8284
http.Handle("/v1/query", gz.GzipHandler(handleWrapper(queryHandler)))
8385
http.Handle("/v1/tables", gz.GzipHandler(handleWrapper(tablesHandler)))
8486
http.Handle("/v1/views", gz.GzipHandler(handleWrapper(viewsHandler)))
85-
http.Handle("/v1/diff", gz.GzipHandler(handleWrapper(diffHandler)))
8687

8788
// Generate the formatted server string
8889
server = fmt.Sprintf("https://%s", com.Conf.Api.ServerName)
@@ -131,7 +132,7 @@ func checkAuth(w http.ResponseWriter, r *http.Request) (loggedInUser string, err
131132
// 2. Extracts the database owner, name, & commitID from the request
132133
// 3. Fetches the database from Minio (with appropriate permission checks)
133134
// 4. Opens the database, returning the connection handle
134-
// This function exists purely because this code is commonly to most of the handlers
135+
// This function exists purely because this code is common to most of the handlers
135136
func collectInfo(w http.ResponseWriter, r *http.Request) (sdb *sqlite.Conn, err error, httpStatus int) {
136137
var loggedInUser string
137138
loggedInUser, err = checkAuth(w, r)
@@ -167,7 +168,8 @@ func collectInfo(w http.ResponseWriter, r *http.Request) (sdb *sqlite.Conn, err
167168
}
168169

169170
// Retrieve database file from Minio, using locally cached version if it's already there
170-
newDB, err := com.RetrieveDatabaseFile(bucket, id)
171+
var newDB string
172+
newDB, err = com.RetrieveDatabaseFile(bucket, id)
171173
if err != nil {
172174
httpStatus = http.StatusNotFound
173175
return

common/types.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,18 @@ type ActivityStats struct {
197197
Viewed []ActivityRow
198198
}
199199

200+
// APIJSONColumn is a copy of the Column type from github.com/gwenn/gosqlite, but including JSON field name info
201+
type APIJSONColumn struct {
202+
Cid int `json:"column_id"`
203+
Name string `json:"name"`
204+
DataType string `json:"data_type"`
205+
NotNull bool `json:"not_null"`
206+
DfltValue string `json:"default_value"`
207+
Pk int `json:"primary_key"`
208+
Autoinc bool `json:"autoinc"`
209+
CollSeq string `json:"collation_seq"`
210+
}
211+
200212
type APIKey struct {
201213
Key string `json:"key"`
202214
DateCreated time.Time `json:"date_created"`

common/userinput.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,34 @@ func GetFormTag(r *http.Request) (tag string, err error) {
259259
return c, nil
260260
}
261261

262+
// Return the table name present in the GET or POST/PUT data.
263+
func GetFormTable(r *http.Request, allowGet bool) (string, error) {
264+
// Retrieve the variable from the GET or POST/PUT data
265+
var t, table string
266+
if allowGet {
267+
t = r.FormValue("table")
268+
} else {
269+
t = r.PostFormValue("table")
270+
}
271+
272+
// If no table name given, return
273+
if t == "" {
274+
return "", nil
275+
}
276+
277+
// Unescape, then validate the owner name
278+
table, err := url.QueryUnescape(t)
279+
if err != nil {
280+
return "", err
281+
}
282+
err = ValidatePGTable(table)
283+
if err != nil {
284+
log.Printf("Validation failed for table name: %s", err)
285+
return "", err
286+
}
287+
return table, nil
288+
}
289+
262290
// Return the username, database, and commit (if any) present in the form data.
263291
func GetFormUDC(r *http.Request) (string, string, string, error) {
264292
// Extract the username

0 commit comments

Comments
 (0)