Skip to content

Commit

Permalink
feat: redefine show tag keys, tag values, field keys
Browse files Browse the repository at this point in the history
Signed-off-by: Young Xu <[email protected]>
  • Loading branch information
xuthus5 committed Jul 27, 2024
1 parent f764244 commit 7c2420c
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 60 deletions.
12 changes: 9 additions & 3 deletions opengemini/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,15 @@ type Client interface {
ShowRetentionPolicies(database string) ([]RetentionPolicy, error)
DropRetentionPolicy(database, retentionPolicy string) error

ShowTagKeys(database, command string) ([]ValuesResult, error)
ShowTagValues(database, command string) ([]ValuesResult, error)
ShowFieldKeys(database, command string) ([]ValuesResult, error)
// ShowTagKeys enumerate all possible results of tag, return {"measurement_name":["TAG1","TAG2"]}
// the best way to set builder from NewTagKeysBuilder
ShowTagKeys(database string, builder TagKeysBuilder) (map[string][]string, error)
// ShowTagValues enumerate all value of a tag key , return ["TAG1","TAG2"]
// the best way to set builder from NewTagValuesBuilder
ShowTagValues(database string, builder TagValuesBuilder) ([]string, error)
// ShowFieldKeys get measurement schema, return {"measurement_name": {"field_name":"field_type"}}
// the best way to set builder from NewFieldKeysBuilder
ShowFieldKeys(database string, builder FieldKeysBuilder) (map[string]map[string]string, error)
// ShowSeries returns the series of specified databases
// return [measurement1,tag1=value1 measurement2,tag2=value2]
ShowSeries(database, command string) ([]string, error)
Expand Down
32 changes: 32 additions & 0 deletions opengemini/field_keys_builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package opengemini

import "strings"

type FieldKeysBuilder interface {
// Measurement query the field keys in a specified measurement, if measurement is not set,
// all measurements in the database will be queried.
Measurement(string) FieldKeysBuilder
Build() string
}

type fieldKeysBuilder struct {
measurement string
}

func (f *fieldKeysBuilder) Measurement(measurement string) FieldKeysBuilder {
f.measurement = measurement
return f
}

func (f *fieldKeysBuilder) Build() string {
var buf strings.Builder
buf.WriteString("SHOW FIELD KEYS")
if f.measurement != "" {
buf.WriteString(" FROM " + f.measurement)
}
return buf.String()
}

func NewFieldKeysBuilder() FieldKeysBuilder {
return &fieldKeysBuilder{}
}
89 changes: 78 additions & 11 deletions opengemini/measurement.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,120 @@ package opengemini

import (
"errors"
"fmt"
)

type ValuesResult struct {
Measurement string
Values []interface{}
}

func (c *client) ShowTagKeys(database, command string) ([]ValuesResult, error) {
func (c *client) ShowTagKeys(database string, builder TagKeysBuilder) (map[string][]string, error) {
if len(database) == 0 {
return nil, errors.New("empty database name")
}
tagKeyResult, err := c.showTagSeriesQuery(database, command)
if builder == nil {
return nil, errors.New("empty command")
}
tagKeyResult, err := c.showTagSeriesQuery(database, builder.Build())
if err != nil {
return nil, err
}
return tagKeyResult, nil
var data = make(map[string][]string)
for _, result := range tagKeyResult {
var tags []string
for _, value := range result.Values {
tags = append(tags, value.(string))
}
data[result.Measurement] = tags
}
return data, nil
}

func (c *client) ShowTagValues(database, command string) ([]ValuesResult, error) {
func (c *client) ShowTagValues(database string, builder TagValuesBuilder) ([]string, error) {
if len(database) == 0 {
return nil, errors.New("empty database name")
}
if len(command) == 0 {
if builder == nil {
return nil, errors.New("empty command")
}

tagValueResult, err := c.showTagFieldQuery(database, command)
queryResult, err := c.Query(Query{Database: database, Command: builder.Build()})
if err != nil {
return nil, err
}
return tagValueResult, nil

if queryResult.hasError() != nil {
return nil, queryResult.hasError()
}

if len(queryResult.Results) == 0 {
return []string{}, nil
}

var values []string
querySeries := queryResult.Results[0].Series

for _, series := range querySeries {
if len(series.Values) != 2 {
continue
}
for _, valRes := range series.Values {
if len(valRes) != 2 {
return []string{}, fmt.Errorf("invalid values: %s", valRes)
}
if strVal, ok := valRes[1].(string); ok {
values = append(values, strVal)
}
}
}

return values, nil
}

func (c *client) ShowFieldKeys(database, command string) ([]ValuesResult, error) {
func (c *client) ShowFieldKeys(database string, builder FieldKeysBuilder) (map[string]map[string]string, error) {
if len(database) == 0 {
return nil, errors.New("empty database name")
}

if len(command) == 0 {
if builder == nil {
return nil, errors.New("empty command")
}

tagKeyResult, err := c.showTagFieldQuery(database, command)
queryResult, err := c.Query(Query{Database: database, Command: builder.Build()})
if err != nil {
return nil, err
}
return tagKeyResult, nil

if queryResult.hasError() != nil {
return nil, queryResult.hasError()
}

if len(queryResult.Results) == 0 {
return nil, nil
}

querySeries := queryResult.Results[0].Series
var value = make(map[string]map[string]string, len(querySeries))

for _, series := range querySeries {
var kv = make(map[string]string, len(series.Values))
for _, valRes := range series.Values {
if len(valRes) != 2 {
return nil, fmt.Errorf("invalid values: %s", valRes)
}
var k, v string
if strVal, ok := valRes[0].(string); ok {
k = strVal
}
if strVal, ok := valRes[1].(string); ok {
v = strVal
}
kv[k] = v
}
value[series.Name] = kv
}
return value, nil
}

func (c *client) ShowSeries(database, command string) ([]string, error) {
Expand Down
57 changes: 55 additions & 2 deletions opengemini/measurement_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package opengemini

import (
"context"
"fmt"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"testing"
"time"
)

func TestClientShowTagKeys(t *testing.T) {
Expand All @@ -16,10 +18,59 @@ func TestClientShowTagKeys(t *testing.T) {
cmd := fmt.Sprintf("CREATE MEASUREMENT %s (tag1 TAG,tag2 TAG,tag3 TAG, field1 INT64 FIELD, field2 BOOL, field3 STRING, field4 FLOAT64)", measurement)
_, err = c.Query(Query{Command: cmd, Database: databaseName})
assert.Nil(t, err)
showKeyCmd := fmt.Sprintf("SHOW TAG KEYS FROM %s limit 3 OFFSET 0", measurement)
// SHOW TAG KEYS FROM MEASUREMENT limit 3 OFFSET 0
showKeyCmd := NewTagKeysBuilder().Limit(3).Measurement(measurement)
tagKeyResult, err := c.ShowTagKeys(databaseName, showKeyCmd)
assert.Nil(t, err)
assert.Equal(t, 1, len(tagKeyResult))
assert.Equal(t, 3, len(tagKeyResult[measurement]))
err = c.DropDatabase(databaseName)
require.Nil(t, err)
}

func TestClientShowTagValues(t *testing.T) {
c := testDefaultClient(t)
databaseName := randomDatabaseName()
err := c.CreateDatabase(databaseName)
require.Nil(t, err)
measurement := randomMeasurement()
var ctx = context.Background()
tag := RandStr(4)
err = c.WritePoint(ctx, databaseName, &Point{
Measurement: measurement,
Precision: PrecisionMillisecond,
Tags: map[string]string{
tag: "t1",
},
Fields: map[string]interface{}{
"field1": "v1",
},
}, func(err error) {

})
require.Nil(t, err)
time.Sleep(time.Second)
err = c.WritePoint(ctx, databaseName, &Point{
Measurement: measurement,
Precision: PrecisionMillisecond,
Tags: map[string]string{
tag: "t2",
},
Fields: map[string]interface{}{
"field2": "v2",
},
}, func(err error) {

})
require.Nil(t, err)
time.Sleep(time.Second * 3)
// SHOW KEY VALUES FROM {MEASUREMENT} WITH KEY = "{tag}"
cmd := NewTagValuesBuilder().Measurement(measurement).Key(tag)
values, err := c.ShowTagValues(databaseName, cmd)
assert.Nil(t, err)
assert.Equal(t, 2, len(values))
assert.EqualValues(t, "t1", values[0])
assert.EqualValues(t, "t2", values[1])
err = c.DropDatabase(databaseName)
require.Nil(t, err)
}
Expand All @@ -33,9 +84,11 @@ func TestClient_ShowFieldKeys(t *testing.T) {
cmd := fmt.Sprintf("CREATE MEASUREMENT %s (tag1 TAG,tag2 TAG,tag3 TAG, field1 INT64 FIELD, field2 BOOL, field3 STRING, field4 FLOAT64)", measurement)
_, err = c.Query(Query{Command: cmd, Database: databaseName})
assert.Nil(t, err)
tagFieldResult, err := c.ShowFieldKeys(databaseName, fmt.Sprintf("SHOW FIELD KEYS FROM %s", measurement))
builder := NewFieldKeysBuilder().Measurement(measurement)
tagFieldResult, err := c.ShowFieldKeys(databaseName, builder)
assert.Nil(t, err)
assert.Equal(t, 1, len(tagFieldResult))
assert.Equal(t, 4, len(tagFieldResult[measurement]))
err = c.DropDatabase(databaseName)
require.Nil(t, err)
}
39 changes: 0 additions & 39 deletions opengemini/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,42 +122,3 @@ func (c *client) showTagSeriesQuery(database, command string) ([]ValuesResult, e
}
return tagSeries, nil
}

func (c *client) showTagFieldQuery(database, command string) ([]ValuesResult, error) {
var tagValueResult []ValuesResult
tagKeyResult, err := c.Query(Query{Database: database, Command: command})
if err != nil {
return tagValueResult, err
}

err = tagKeyResult.hasError()
if err != nil {
return tagValueResult, fmt.Errorf("get tagKeyResult failed, error: %s", err)
}
if len(tagKeyResult.Results) == 0 {
return tagValueResult, nil
}

values := tagKeyResult.Results[0].Series
tagValueResult = make([]ValuesResult, 0, len(values))
for _, res := range values {
tagValueRes := new(ValuesResult)
for _, valRes := range res.Values {
tagValue := new(keyValue)
if len(valRes) < 2 {
return []ValuesResult{}, fmt.Errorf("invalid values: %s", valRes)
}
if strVal, ok := valRes[0].(string); ok {
tagValue.Name = strVal
}
if strVal, ok := valRes[1].(string); ok {
tagValue.Value = strVal
}
tagValueRes.Values = append(tagValueRes.Values, *tagValue)
}
tagValueRes.Measurement = res.Name
tagValueResult = append(tagValueResult, *tagValueRes)
}
return tagValueResult, nil

}
58 changes: 58 additions & 0 deletions opengemini/tag_keys_builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package opengemini

import (
"strconv"
"strings"
)

type TagKeysBuilder interface {
// Measurement query the tag keys in a specified measurement, if measurement is not set,
// all measurements in the database will be queried.
Measurement(measurement string) TagKeysBuilder
// Limit the number of entries returned by tag keys
Limit(limit int) TagKeysBuilder
// Offset skip the number of entries returned by tag keys
Offset(offset int) TagKeysBuilder
// Build generate query sql
Build() string
}

type tagKeysBuilder struct {
measurement string
limit int
offset int
}

func (t *tagKeysBuilder) Measurement(measurement string) TagKeysBuilder {
t.measurement = measurement
return t
}

func (t *tagKeysBuilder) Limit(limit int) TagKeysBuilder {
t.limit = limit
return t
}

func (t *tagKeysBuilder) Offset(offset int) TagKeysBuilder {
t.offset = offset
return t
}

func (t *tagKeysBuilder) Build() string {
var buf strings.Builder
buf.WriteString("SHOW TAG KEYS")
if t.measurement != "" {
buf.WriteString(" FROM " + t.measurement)
}
if t.limit > 0 {
buf.WriteString(" LIMIT " + strconv.Itoa(t.limit))
}
if t.offset > 0 {
buf.WriteString(" OFFSET " + strconv.Itoa(t.offset))
}
return buf.String()
}

func NewTagKeysBuilder() TagKeysBuilder {
return &tagKeysBuilder{}
}
Loading

0 comments on commit 7c2420c

Please sign in to comment.