Add support for uint64 in the clients

pull/8921/head
Jonathan A. Sternberg 2017-10-04 15:53:45 -05:00
parent e0746762d9
commit 2f47c3d28f
6 changed files with 104 additions and 35 deletions

View File

@ -164,6 +164,14 @@ func writePoints(clnt client.Client) {
}
```
#### Uint64 Support
The `uint64` data type is supported if your server is version `1.4.0` or
greater. To write a data point as an unsigned integer, you must insert
the point as `uint64`. You cannot use `uint` or any of the other
derivatives because previous versions of the client have supported
writing those types as an integer.
### Querying Data
One nice advantage of using **InfluxDB** the ability to query your data using familiar

View File

@ -785,7 +785,7 @@ func (c *Client) Addr() string {
func checkPointTypes(p Point) error {
for _, v := range p.Fields {
switch v.(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, float32, float64, bool, string, nil:
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool, string, nil:
return nil
default:
return fmt.Errorf("unsupported point type: %T", v)

View File

@ -307,6 +307,12 @@ func TestClient_BasicAuth(t *testing.T) {
func TestClient_Write(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
in, err := ioutil.ReadAll(r.Body)
if err != nil {
t.Fatalf("unexpected error: %s", err)
} else if have, want := strings.TrimSpace(string(in)), `m0,host=server01 v1=2,v2=2i,v3=2u,v4="foobar",v5=true 0`; have != want {
t.Errorf("unexpected write protocol: %s != %s", have, want)
}
var data client.Response
w.WriteHeader(http.StatusNoContent)
_ = json.NewEncoder(w).Encode(data)
@ -320,7 +326,24 @@ func TestClient_Write(t *testing.T) {
t.Fatalf("unexpected error. expected %v, actual %v", nil, err)
}
bp := client.BatchPoints{}
bp := client.BatchPoints{
Points: []client.Point{
{
Measurement: "m0",
Tags: map[string]string{
"host": "server01",
},
Time: time.Unix(0, 0).UTC(),
Fields: map[string]interface{}{
"v1": float64(2),
"v2": int64(2),
"v3": uint64(2),
"v4": "foobar",
"v5": true,
},
},
},
}
r, err := c.Write(bp)
if err != nil {
t.Fatalf("unexpected error. expected %v, actual %v", nil, err)
@ -724,36 +747,6 @@ func TestClient_NoTimeout(t *testing.T) {
}
}
func TestClient_WriteUint64(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var data client.Response
w.WriteHeader(http.StatusNoContent)
_ = json.NewEncoder(w).Encode(data)
}))
defer ts.Close()
u, _ := url.Parse(ts.URL)
config := client.Config{URL: *u}
c, err := client.NewClient(config)
if err != nil {
t.Fatalf("unexpected error. expected %v, actual %v", nil, err)
}
bp := client.BatchPoints{
Points: []client.Point{
{
Fields: map[string]interface{}{"value": uint64(10)},
},
},
}
r, err := c.Write(bp)
if err == nil {
t.Fatalf("unexpected error. expected err, actual %v", err)
}
if r != nil {
t.Fatalf("unexpected response. expected %v, actual %v", nil, r)
}
}
func TestClient_ParseConnectionString_IPv6(t *testing.T) {
path := "[fdf5:9ede:1875:0:a9ee:a600:8fe3:d495]:8086"
u, err := client.ParseConnectionString(path, false)

View File

@ -3,6 +3,7 @@ package client
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"reflect"
@ -330,6 +331,12 @@ func TestClient_Concurrent_Use(t *testing.T) {
func TestClient_Write(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
in, err := ioutil.ReadAll(r.Body)
if err != nil {
t.Fatalf("unexpected error: %s", err)
} else if have, want := strings.TrimSpace(string(in)), `m0,host=server01 v1=2,v2=2i,v3=2u,v4="foobar",v5=true 0`; have != want {
t.Errorf("unexpected write protocol: %s != %s", have, want)
}
var data Response
w.WriteHeader(http.StatusNoContent)
_ = json.NewEncoder(w).Encode(data)
@ -344,6 +351,24 @@ func TestClient_Write(t *testing.T) {
if err != nil {
t.Errorf("unexpected error. expected %v, actual %v", nil, err)
}
pt, err := NewPoint(
"m0",
map[string]string{
"host": "server01",
},
map[string]interface{}{
"v1": float64(2),
"v2": int64(2),
"v3": uint64(2),
"v4": "foobar",
"v5": true,
},
time.Unix(0, 0).UTC(),
)
if err != nil {
t.Errorf("unexpected error. expected %v, actual %v", nil, err)
}
bp.AddPoint(pt)
err = c.Write(bp)
if err != nil {
t.Errorf("unexpected error. expected %v, actual %v", nil, err)

View File

@ -2248,6 +2248,9 @@ func appendField(b []byte, k string, v interface{}) []byte {
case int:
b = strconv.AppendInt(b, int64(v), 10)
b = append(b, 'i')
case uint64:
b = strconv.AppendUint(b, v, 10)
b = append(b, 'u')
case uint32:
b = strconv.AppendInt(b, int64(v), 10)
b = append(b, 'i')
@ -2257,10 +2260,9 @@ func appendField(b []byte, k string, v interface{}) []byte {
case uint8:
b = strconv.AppendInt(b, int64(v), 10)
b = append(b, 'i')
// TODO: 'uint' should be considered just as "dangerous" as a uint64,
// perhaps the value should be checked and capped at MaxInt64? We could
// then include uint64 as an accepted value
case uint:
// TODO: 'uint' should be converted to writing as an unsigned integer,
// but we cannot since that would break backwards compatibility.
b = strconv.AppendInt(b, int64(v), 10)
b = append(b, 'i')
case float32:

View File

@ -40,6 +40,47 @@ func TestMarshal(t *testing.T) {
}
}
func TestMarshalFields(t *testing.T) {
for _, tt := range []struct {
name string
value interface{}
exp string
}{
{
name: "Float",
value: float64(2),
exp: `value=2`,
},
{
name: "Integer",
value: int64(2),
exp: `value=2i`,
},
{
name: "Unsigned",
value: uint64(2),
exp: `value=2u`,
},
{
name: "String",
value: "foobar",
exp: `value="foobar"`,
},
{
name: "Boolean",
value: true,
exp: `value=true`,
},
} {
t.Run(tt.name, func(t *testing.T) {
fields := map[string]interface{}{"value": tt.value}
if have, want := models.Fields(fields).MarshalBinary(), []byte(tt.exp); !bytes.Equal(have, want) {
t.Fatalf("unexpected field output: %s != %s", string(have), string(want))
}
})
}
}
func TestTags_HashKey(t *testing.T) {
tags = models.NewTags(map[string]string{"A FOO": "bar", "APPLE": "orange", "host": "serverA", "region": "uswest"})
got := tags.HashKey()