Add top-level "results" key
This brings the API output into line with the API specification.pull/1385/head
parent
155bc9a531
commit
a197d16ac8
|
@ -44,7 +44,7 @@ func NewClient(c Config) (*Client, error) {
|
|||
return &client, nil
|
||||
}
|
||||
|
||||
func (c *Client) Query(q Query) (influxdb.Results, error) {
|
||||
func (c *Client) Query(q Query) (*influxdb.Results, error) {
|
||||
u := c.url
|
||||
|
||||
u.Path = "query"
|
||||
|
@ -64,10 +64,10 @@ func (c *Client) Query(q Query) (influxdb.Results, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return results, nil
|
||||
return &results, nil
|
||||
}
|
||||
|
||||
func (c *Client) Write(writes ...Write) (influxdb.Results, error) {
|
||||
func (c *Client) Write(writes ...Write) (*influxdb.Results, error) {
|
||||
c.url.Path = "write"
|
||||
type data struct {
|
||||
Points []influxdb.Point `json:"points"`
|
||||
|
@ -94,7 +94,7 @@ func (c *Client) Write(writes ...Write) (influxdb.Results, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return results, nil
|
||||
return &results, nil
|
||||
}
|
||||
|
||||
func (c *Client) Ping() (time.Duration, string, error) {
|
||||
|
|
|
@ -111,7 +111,7 @@ func (c *cli) executeQuery(query string) {
|
|||
if err != nil {
|
||||
fmt.Printf("ERR: %s\n", err)
|
||||
}
|
||||
for _, r := range results {
|
||||
for _, r := range results.Results {
|
||||
var i interface{}
|
||||
if r.Err != nil {
|
||||
i = r.Err
|
||||
|
|
|
@ -331,12 +331,9 @@ func httpResults(w http.ResponseWriter, results influxdb.Results, pretty bool) {
|
|||
|
||||
// httpError writes an error to the client in a standard format.
|
||||
func httpError(w http.ResponseWriter, error string, code int) {
|
||||
var results influxdb.Results
|
||||
results = append(results, &influxdb.Result{Err: errors.New(error)})
|
||||
|
||||
w.Header().Add("content-type", "application/json")
|
||||
w.WriteHeader(code)
|
||||
_ = json.NewEncoder(w).Encode(results)
|
||||
_ = json.NewEncoder(w).Encode(influxdb.Results{Err: errors.New(error)})
|
||||
}
|
||||
|
||||
// Filters and filter helpers
|
||||
|
|
|
@ -30,7 +30,7 @@ func TestHandler_Databases(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, map[string]string{"q": "SHOW DATABASES"}, nil, "")
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"rows":[{"columns":["Name"],"values":[["bar"],["foo"]]}]}]` {
|
||||
} else if body != `{"results":[{"rows":[{"columns":["Name"],"values":[["bar"],["foo"]]}]}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -45,25 +45,27 @@ func TestHandler_DatabasesPrettyPrinted(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, map[string]string{"q": "SHOW DATABASES", "pretty": "true"}, nil, "")
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[
|
||||
{
|
||||
"rows": [
|
||||
{
|
||||
"columns": [
|
||||
"Name"
|
||||
],
|
||||
"values": [
|
||||
[
|
||||
"bar"
|
||||
} else if body != `{
|
||||
"results": [
|
||||
{
|
||||
"rows": [
|
||||
{
|
||||
"columns": [
|
||||
"Name"
|
||||
],
|
||||
[
|
||||
"foo"
|
||||
"values": [
|
||||
[
|
||||
"bar"
|
||||
],
|
||||
[
|
||||
"foo"
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]` {
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +78,7 @@ func TestHandler_CreateDatabase(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, map[string]string{"q": "CREATE DATABASE foo"}, nil, "")
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{}]` {
|
||||
} else if body != `{"results":[{}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +103,7 @@ func TestHandler_CreateDatabase_Conflict(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, map[string]string{"q": "CREATE DATABASE foo"}, nil, "")
|
||||
if status != http.StatusInternalServerError {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"error":"database exists"}]` {
|
||||
} else if body != `{"results":[{"error":"database exists"}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +117,7 @@ func TestHandler_DeleteDatabase(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, map[string]string{"q": "DROP DATABASE foo"}, nil, "")
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{}]` {
|
||||
} else if body != `{"results":[{}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +130,7 @@ func TestHandler_DeleteDatabase_NotFound(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, map[string]string{"q": "DROP DATABASE bar"}, nil, "")
|
||||
if status != http.StatusInternalServerError {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"error":"database not found"}]` {
|
||||
} else if body != `{"results":[{"error":"database not found"}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +146,7 @@ func TestHandler_RetentionPolicies(t *testing.T) {
|
|||
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"rows":[{"columns":["Name"],"values":[["bar"]]}]}]` {
|
||||
} else if body != `{"results":[{"rows":[{"columns":["Name"],"values":[["bar"]]}]}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +160,7 @@ func TestHandler_RetentionPolicies_DatabaseNotFound(t *testing.T) {
|
|||
|
||||
if status != http.StatusInternalServerError {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"error":"database not found"}]` {
|
||||
} else if body != `{"results":[{"error":"database not found"}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -174,7 +176,7 @@ func TestHandler_CreateRetentionPolicy(t *testing.T) {
|
|||
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{}]` {
|
||||
} else if body != `{"results":[{}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -302,7 +304,7 @@ func TestHandler_DeleteRetentionPolicy(t *testing.T) {
|
|||
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{}]` {
|
||||
} else if body != `{"results":[{}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -317,7 +319,7 @@ func TestHandler_DeleteRetentionPolicy_DatabaseNotFound(t *testing.T) {
|
|||
|
||||
if status != http.StatusInternalServerError {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"error":"database not found"}]` {
|
||||
} else if body != `{"results":[{"error":"database not found"}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -333,7 +335,7 @@ func TestHandler_DeleteRetentionPolicy_NotFound(t *testing.T) {
|
|||
|
||||
if status != http.StatusInternalServerError {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"error":"retention policy not found"}]` {
|
||||
} else if body != `{"results":[{"error":"retention policy not found"}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -360,7 +362,7 @@ func TestHandler_Users_NoUsers(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, query, nil, "")
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"rows":[{"columns":["User"]}]}]` {
|
||||
} else if body != `{"results":[{"rows":[{"columns":["User"]}]}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -375,7 +377,7 @@ func TestHandler_Users_OneUser(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, query, nil, "")
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"rows":[{"columns":["User"],"values":[["jdoe"]]}]}]` {
|
||||
} else if body != `{"results":[{"rows":[{"columns":["User"],"values":[["jdoe"]]}]}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -392,7 +394,7 @@ func TestHandler_Users_MultipleUsers(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, query, nil, "")
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"rows":[{"columns":["User"],"values":[["csmith"],["jdoe"],["mclark"]]}]}]` {
|
||||
} else if body != `{"results":[{"rows":[{"columns":["User"],"values":[["csmith"],["jdoe"],["mclark"]]}]}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -406,7 +408,7 @@ func TestHandler_CreateUser(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, query, nil, "")
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{}]` {
|
||||
} else if body != `{"results":[{}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -420,7 +422,7 @@ func TestHandler_CreateUser_BadRequest(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, query, nil, "")
|
||||
if status != http.StatusBadRequest {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"error":"error parsing query: found 0, expected identifier at line 1, char 13"}]` {
|
||||
} else if body != `{"error":"error parsing query: found 0, expected identifier at line 1, char 13"}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -434,7 +436,7 @@ func TestHandler_CreateUser_BadRequest_NoName(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, query, nil, "")
|
||||
if status != http.StatusBadRequest {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"error":"error parsing query: found WITH, expected identifier at line 1, char 13"}]` {
|
||||
} else if body != `{"error":"error parsing query: found WITH, expected identifier at line 1, char 13"}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -448,7 +450,7 @@ func TestHandler_CreateUser_BadRequest_NoPassword(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, query, nil, "")
|
||||
if status != http.StatusBadRequest {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"error":"error parsing query: found EOF, expected WITH at line 1, char 18"}]` {
|
||||
} else if body != `{"error":"error parsing query: found EOF, expected WITH at line 1, char 18"}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -499,7 +501,7 @@ func TestHandler_DeleteUser(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, query, nil, "")
|
||||
if status != http.StatusOK {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{}]` {
|
||||
} else if body != `{"results":[{}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
@ -513,7 +515,7 @@ func TestHandler_DeleteUser_UserNotFound(t *testing.T) {
|
|||
status, body := MustHTTP("GET", s.URL+`/query`, query, nil, "")
|
||||
if status != http.StatusInternalServerError {
|
||||
t.Fatalf("unexpected status: %d", status)
|
||||
} else if body != `[{"error":"user not found"}]` {
|
||||
} else if body != `{"results":[{"error":"user not found"}]}` {
|
||||
t.Fatalf("unexpected body: %s", body)
|
||||
}
|
||||
}
|
||||
|
|
35
server.go
35
server.go
|
@ -1517,13 +1517,11 @@ func (s *Server) ReadSeries(database, retentionPolicy, name string, tags map[str
|
|||
func (s *Server) ExecuteQuery(q *influxql.Query, database string, user *User) Results {
|
||||
// Authorize user to execute the query.
|
||||
if err := Authorize(user, q, database); err != nil {
|
||||
return Results{
|
||||
{Err: err},
|
||||
}
|
||||
return Results{Err: err}
|
||||
}
|
||||
|
||||
// Build empty resultsets.
|
||||
results := make(Results, len(q.Statements))
|
||||
results := Results{Results: make([]*Result, len(q.Statements))}
|
||||
|
||||
// Execute each statement.
|
||||
for i, stmt := range q.Statements {
|
||||
|
@ -1580,16 +1578,16 @@ func (s *Server) ExecuteQuery(q *influxql.Query, database string, user *User) Re
|
|||
}
|
||||
|
||||
// If an error occurs then stop processing remaining statements.
|
||||
results[i] = res
|
||||
results.Results[i] = res
|
||||
if res.Err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Fill any empty results after error.
|
||||
for i, res := range results {
|
||||
for i, res := range results.Results {
|
||||
if res == nil {
|
||||
results[i] = &Result{Err: ErrNotExecuted}
|
||||
results.Results[i] = &Result{Err: ErrNotExecuted}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1936,12 +1934,31 @@ func (r *Result) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
|
||||
// Results represents a list of statement results.
|
||||
type Results []*Result
|
||||
type Results struct {
|
||||
Results []*Result
|
||||
Err error
|
||||
}
|
||||
|
||||
func (r Results) MarshalJSON() ([]byte, error) {
|
||||
// Define a struct that outputs "error" as a string.
|
||||
var o struct {
|
||||
Results []*Result `json:"results,omitempty"`
|
||||
Err string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// Copy fields to output struct.
|
||||
o.Results = r.Results
|
||||
if r.Err != nil {
|
||||
o.Err = r.Err.Error()
|
||||
}
|
||||
|
||||
return json.Marshal(&o)
|
||||
}
|
||||
|
||||
// Error returns the first error from any statement.
|
||||
// Returns nil if no errors occurred on any statements.
|
||||
func (a Results) Error() error {
|
||||
for _, r := range a {
|
||||
for _, r := range a.Results {
|
||||
if r.Err != nil {
|
||||
return r.Err
|
||||
}
|
||||
|
|
|
@ -712,10 +712,10 @@ func TestServer_ExecuteQuery(t *testing.T) {
|
|||
|
||||
// Select data from the server.
|
||||
results := s.ExecuteQuery(MustParseQuery("SELECT sum(value) FROM cpu"), "foo", nil)
|
||||
if len(results) != 1 {
|
||||
t.Fatalf("unexpected result count: %d", len(results))
|
||||
if len(results.Results) != 1 {
|
||||
t.Fatalf("unexpected result count: %d", len(results.Results))
|
||||
}
|
||||
if res := results[0]; res.Err != nil {
|
||||
if res := results.Results[0]; res.Err != nil {
|
||||
t.Fatalf("unexpected error: %s", res.Err)
|
||||
} else if len(res.Rows) != 1 {
|
||||
t.Fatalf("unexpected row count: %d", len(res.Rows))
|
||||
|
|
Loading…
Reference in New Issue