mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
Add endpoint for database deletion.
Executing a request against `DELETE /db` will now delete a database. curl -X DELETE "http://localhost:15000/db" -d '{"db":"d"}'
This commit is contained in:
parent
138355c155
commit
56aea09ce1
4 changed files with 130 additions and 0 deletions
34
handler.go
34
handler.go
|
|
@ -106,6 +106,13 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
default:
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
case "/db":
|
||||
switch r.Method {
|
||||
case "DELETE":
|
||||
h.handleDeleteDB(w, r)
|
||||
default:
|
||||
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||
}
|
||||
case "/db/attr/diff":
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
|
|
@ -264,6 +271,33 @@ type sliceMaxResponse struct {
|
|||
SliceMax uint64 `json:"SliceMax"`
|
||||
}
|
||||
|
||||
// handleDeleteDB handles DELETE /db request.
|
||||
func (h *Handler) handleDeleteDB(w http.ResponseWriter, r *http.Request) {
|
||||
// Decode request.
|
||||
var req deleteDBRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete database from the index.
|
||||
if err := h.Index.DeleteDB(req.DB); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Encode response.
|
||||
if err := json.NewEncoder(w).Encode(deleteDBResponse{}); err != nil {
|
||||
h.logger().Printf("response encoding error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
type deleteDBRequest struct {
|
||||
DB string `json:"db"`
|
||||
}
|
||||
|
||||
type deleteDBResponse struct{}
|
||||
|
||||
// handlePostDBAttrDiff handles POST /db/attr/diff requests.
|
||||
func (h *Handler) handlePostDBAttrDiff(w http.ResponseWriter, r *http.Request) {
|
||||
// Decode request.
|
||||
|
|
|
|||
|
|
@ -416,6 +416,42 @@ func TestHandler_Query_ErrParse(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Ensure the handler can delete a database.
|
||||
func TestHandler_DB_Delete(t *testing.T) {
|
||||
idx := MustOpenIndex()
|
||||
defer idx.Close()
|
||||
|
||||
s := NewServer()
|
||||
s.Handler.Index = idx.Index
|
||||
defer s.Close()
|
||||
|
||||
// Create database.
|
||||
if _, err := idx.CreateDBIfNotExists("d"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Send request to delete database.
|
||||
resp, err := http.DefaultClient.Do(MustNewHTTPRequest("DELETE", s.URL+"/db", strings.NewReader(`{"db":"d"}`)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Verify body response.
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", resp.StatusCode)
|
||||
} else if buf, err := ioutil.ReadAll(resp.Body); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if string(buf) != "{}\n" {
|
||||
t.Fatalf("unexpected response body: %s", buf)
|
||||
}
|
||||
|
||||
// Verify database is gone.
|
||||
if idx.DB("d") != nil {
|
||||
t.Fatal("expected nil database")
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the handler can return data in differing blocks for a database.
|
||||
func TestHandler_DB_AttrStore_Diff(t *testing.T) {
|
||||
idx := MustOpenIndex()
|
||||
|
|
|
|||
27
index.go
27
index.go
|
|
@ -183,6 +183,33 @@ func (i *Index) createDBIfNotExists(name string) (*DB, error) {
|
|||
return db, nil
|
||||
}
|
||||
|
||||
// DeleteDB removes a database from the index.
|
||||
func (i *Index) DeleteDB(name string) error {
|
||||
i.mu.Lock()
|
||||
defer i.mu.Unlock()
|
||||
|
||||
// Ignore if database doesn't exist.
|
||||
db := i.db(name)
|
||||
if db == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close database.
|
||||
if err := db.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete database directory.
|
||||
if err := os.RemoveAll(i.DBPath(name)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove reference.
|
||||
delete(i.dbs, name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Frame returns the frame for a database and name.
|
||||
func (i *Index) Frame(db, name string) *Frame {
|
||||
d := i.DB(db)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,39 @@ import (
|
|||
"github.com/umbel/pilosa/pql"
|
||||
)
|
||||
|
||||
// Ensure index can delete a database and its underlying files.
|
||||
func TestIndex_DeleteDB(t *testing.T) {
|
||||
idx := MustOpenIndex()
|
||||
defer idx.Close()
|
||||
|
||||
// Write bits to separate databases.
|
||||
f0 := idx.MustCreateFragmentIfNotExists("d0", "f", 0)
|
||||
if _, err := f0.SetBit(100, 200, nil, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f1 := idx.MustCreateFragmentIfNotExists("d1", "f", 0)
|
||||
if _, err := f1.SetBit(100, 200, nil, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Ensure d0 exists.
|
||||
if _, err := os.Stat(idx.DBPath("d0")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Delete d0.
|
||||
if err := idx.DeleteDB("d0"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Ensure d0 files are removed & d1 still exists.
|
||||
if _, err := os.Stat(idx.DBPath("d0")); !os.IsNotExist(err) {
|
||||
t.Fatal("expected d0 file deletion")
|
||||
} else if _, err := os.Stat(idx.DBPath("d1")); err != nil {
|
||||
t.Fatal("expected d1 files to still exist", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure index can sync with a remote index.
|
||||
func TestIndexSyncer_SyncIndex(t *testing.T) {
|
||||
cluster := NewCluster(2)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue