mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
validate db and frame
This commit is contained in:
parent
261e327014
commit
c034293967
3 changed files with 173 additions and 4 deletions
2
db.go
2
db.go
|
|
@ -478,7 +478,7 @@ func MergeSchemas(a, b []*DBInfo) []*DBInfo {
|
|||
|
||||
// DBOptions represents options to set when initializing a db.
|
||||
type DBOptions struct {
|
||||
ColumnLabel string `json:"columnLabel,omitempty"`
|
||||
ColumnLabel string `json:"columnLabel,omitempty" valid:"required,string"`
|
||||
}
|
||||
|
||||
// hasTime returns true if a contains a non-nil time.
|
||||
|
|
|
|||
89
handler.go
89
handler.go
|
|
@ -17,6 +17,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"bytes"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/pilosa/pilosa/internal"
|
||||
"github.com/pilosa/pilosa/pql"
|
||||
|
|
@ -321,6 +322,16 @@ type sliceMaxResponse struct {
|
|||
|
||||
// handlePostDB handles POST /db request.
|
||||
func (h *Handler) handlePostDB(w http.ResponseWriter, r *http.Request) {
|
||||
var err error
|
||||
// Copy request body for validation
|
||||
buf, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
rdr2 := ioutil.NopCloser(bytes.NewBuffer(buf))
|
||||
r.Body = rdr2
|
||||
|
||||
// Decode request.
|
||||
var req postDBRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
|
|
@ -328,8 +339,15 @@ func (h *Handler) handlePostDB(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// Validate request
|
||||
err = h.validateRequest(buf, r.URL.Path)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Create database.
|
||||
_, err := h.Index.CreateDB(req.DB, req.Options)
|
||||
_, err = h.Index.CreateDB(req.DB, req.Options)
|
||||
if err == ErrDatabaseExists {
|
||||
http.Error(w, err.Error(), http.StatusConflict)
|
||||
return
|
||||
|
|
@ -344,9 +362,57 @@ func (h *Handler) handlePostDB(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
// Validate request body for db/frame creation
|
||||
func (h *Handler) validateRequest(r []byte, path string) error {
|
||||
var data map[string]interface{}
|
||||
|
||||
err := json.Unmarshal(r, &data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
option, ok := data["options"]
|
||||
if len(data) >= 2 && !ok {
|
||||
return errors.New("options needs to be provided")
|
||||
} else if ok {
|
||||
err = h.validateOptions(path, option.(map[string]interface{}))
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid options: %s", option.(map[string]interface{}))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// Validate options in request body for db/frame creation, make sure key and value for columnLabel/rowLable is correct
|
||||
func (h Handler) validateOptions(path string, options map[string]interface{}) error {
|
||||
switch path {
|
||||
case "/db":
|
||||
if _, ok := options["columnLabel"]; !ok && len(options) > 0 {
|
||||
return errors.New("columnLabel is not provided")
|
||||
} else if ok {
|
||||
err := ValidateName(options["columnLabel"].(string))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case "/frame":
|
||||
if _, ok := options["rowLabel"]; !ok && len(options) > 0 {
|
||||
return errors.New("rowLabel is not provided")
|
||||
} else if ok {
|
||||
err := ValidateName(options["rowLabel"].(string))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type postDBRequest struct {
|
||||
DB string `json:"db"`
|
||||
Options DBOptions `json:"options"`
|
||||
Options DBOptions `json:"options" valid:"json"`
|
||||
}
|
||||
|
||||
type postDBResponse struct{}
|
||||
|
|
@ -478,6 +544,23 @@ type postDBAttrDiffResponse struct {
|
|||
|
||||
// handlePostFrame handles POST /frame request.
|
||||
func (h *Handler) handlePostFrame(w http.ResponseWriter, r *http.Request) {
|
||||
var err error
|
||||
// Copy request body for validation
|
||||
buf, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
rdr2 := ioutil.NopCloser(bytes.NewBuffer(buf))
|
||||
r.Body = rdr2
|
||||
|
||||
// Validate request
|
||||
err = h.validateRequest(buf, r.URL.Path)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Decode request.
|
||||
var req postFrameRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
|
|
@ -493,7 +576,7 @@ func (h *Handler) handlePostFrame(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// Create frame.
|
||||
_, err := db.CreateFrame(req.Frame, req.Options)
|
||||
_, err = db.CreateFrame(req.Frame, req.Options)
|
||||
if err == ErrFrameExists {
|
||||
http.Error(w, err.Error(), http.StatusConflict)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"fmt"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/pilosa/pilosa"
|
||||
"github.com/pilosa/pilosa/internal"
|
||||
|
|
@ -868,3 +869,88 @@ func MustReadAll(r io.Reader) []byte {
|
|||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// Ensure that options needs to be provided to set columnLabel when create DB
|
||||
func TestHandler_DB_Options(t *testing.T) {
|
||||
idx := MustOpenIndex()
|
||||
defer idx.Close()
|
||||
|
||||
s := NewServer()
|
||||
s.Handler.Index = idx.Index
|
||||
defer s.Close()
|
||||
|
||||
resp, err := http.DefaultClient.Do(MustNewHTTPRequest("POST", s.URL+"/db", strings.NewReader(`{"db": "sample-db", "columnLabel": "location"}`)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Verify body response.
|
||||
if resp.StatusCode != http.StatusBadRequest {
|
||||
t.Fatalf("unexpected status: %d", resp.StatusCode)
|
||||
} else if buf, err := ioutil.ReadAll(resp.Body); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if string(buf) != "options needs to be provided"+"\n" {
|
||||
fmt.Println(string(buf) == "options needs to be provided")
|
||||
t.Fatalf("unexpected response body: %s", buf)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Ensure that rowLabel is provided as an options when create frame
|
||||
func TestHandler_Frame_Options(t *testing.T) {
|
||||
idx := MustOpenIndex()
|
||||
defer idx.Close()
|
||||
|
||||
s := NewServer()
|
||||
s.Handler.Index = idx.Index
|
||||
defer s.Close()
|
||||
|
||||
// Create database.
|
||||
if _, err := idx.CreateDBIfNotExists("sample-db", pilosa.DBOptions{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(MustNewHTTPRequest("POST", s.URL+"/frame", strings.NewReader(`{"db": "sample-db", "frame": "test", "options": {"columnLabel": "location"}}`)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Verify body response.
|
||||
if resp.StatusCode != http.StatusBadRequest {
|
||||
t.Fatalf("unexpected status: %d", resp.StatusCode)
|
||||
} else if buf, err := ioutil.ReadAll(resp.Body); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if string(buf) != "invalid options: map[columnLabel:location]"+"\n" {
|
||||
t.Fatalf("unexpected response body: %s", buf)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that rowLabel is provided as an options when create frame
|
||||
func TestHandler_OptionsValue(t *testing.T) {
|
||||
idx := MustOpenIndex()
|
||||
defer idx.Close()
|
||||
|
||||
s := NewServer()
|
||||
s.Handler.Index = idx.Index
|
||||
defer s.Close()
|
||||
|
||||
// Create database.
|
||||
if _, err := idx.CreateDBIfNotExists("sample-db", pilosa.DBOptions{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(MustNewHTTPRequest("POST", s.URL+"/frame", strings.NewReader(`{"db": "sample-db", "options": {"rowLabel": "///"}}`)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Verify body response.
|
||||
if resp.StatusCode != http.StatusBadRequest {
|
||||
t.Fatalf("unexpected status: %d", resp.StatusCode)
|
||||
} else if buf, err := ioutil.ReadAll(resp.Body); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if string(buf) != "invalid options: map[rowLabel:///]"+"\n" {
|
||||
t.Fatalf("unexpected response body: %s", buf)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue