Skip to content

Commit

Permalink
Add GRAPH.CONFIG and RedisGraph refactoring (#201)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikhail-vl authored May 18, 2021
1 parent 9b78929 commit 8946bed
Show file tree
Hide file tree
Showing 12 changed files with 228 additions and 62 deletions.
2 changes: 2 additions & 0 deletions pkg/data-frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ func addFrameFieldsFromArray(values []interface{}, frame *data.Frame) *data.Fram
frame.Fields = append(frame.Fields, data.NewField(key, nil, []string{value}))
case int64:
frame.Fields = append(frame.Fields, data.NewField(key, nil, []int64{v}))
case float64:
frame.Fields = append(frame.Fields, data.NewField(key, nil, []float64{v}))
default:
log.DefaultLogger.Error("addFrameFieldsFromArray", "Conversion Error", "Unsupported Value type")
}
Expand Down
9 changes: 9 additions & 0 deletions pkg/models/redis-graph.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
package models

/**
* Commands
*/
const GraphConfig = "graph.config"
const GraphExplain = "graph.explain"
const GraphProfile = "graph.profile"
const GraphQuery = "graph.query"
const GraphSlowlog = "graph.slowlog"

/**
* Represents node
*/
Expand Down
11 changes: 7 additions & 4 deletions pkg/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
"github.com/mediocregopher/radix/v3/resp/resp2"
"github.com/redisgrafana/grafana-redis-datasource/pkg/models"
)

/**
Expand Down Expand Up @@ -118,14 +119,16 @@ func query(ctx context.Context, query backend.DataQuery, client redisClient, qm
/**
* Redis Graph
*/
case "graph.query":
case models.GraphQuery:
return queryGraphQuery(qm, client)
case "graph.slowlog":
case models.GraphSlowlog:
return queryGraphSlowlog(qm, client)
case "graph.explain":
case models.GraphExplain:
return queryGraphExplain(qm, client)
case "graph.profile":
case models.GraphProfile:
return queryGraphProfile(qm, client)
case models.GraphConfig:
return queryGraphConfig(qm, client)

/**
* Default
Expand Down
10 changes: 6 additions & 4 deletions pkg/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/mediocregopher/radix/v3/resp/resp2"
"github.com/redisgrafana/grafana-redis-datasource/pkg/models"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -46,10 +47,11 @@ func TestQuery(t *testing.T) {
{queryModel{Command: "rg.pydumpreqs"}},
{queryModel{Command: "xrange"}},
{queryModel{Command: "xrevrange"}},
{queryModel{Command: "graph.query"}},
{queryModel{Command: "graph.slowlog"}},
{queryModel{Command: "graph.explain"}},
{queryModel{Command: "graph.profile"}},
{queryModel{Command: models.GraphConfig}},
{queryModel{Command: models.GraphExplain}},
{queryModel{Command: models.GraphProfile}},
{queryModel{Command: models.GraphQuery}},
{queryModel{Command: models.GraphSlowlog}},
}

// Run Tests
Expand Down
35 changes: 29 additions & 6 deletions pkg/redis-graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
*/
func queryGraphQuery(qm queryModel, client redisClient) backend.DataResponse {
response := backend.DataResponse{}

var result []interface{}

// Run command
Expand Down Expand Up @@ -199,7 +198,7 @@ func findAllNodesAndEdges(input interface{}) ([]models.NodeEntry, []models.EdgeE
}

// Add property
propString := fmt.Sprintf("\"%s\"=\"%s\"", propertyArray[0], value)
propString := fmt.Sprintf("%s: %s", propertyArray[0], value)
props = append(props, propString)
}

Expand Down Expand Up @@ -244,7 +243,7 @@ func findAllNodesAndEdges(input interface{}) ([]models.NodeEntry, []models.EdgeE
}

// Add property
propString := fmt.Sprintf("\"%s\"=\"%s\"", propertyArray[0], value)
propString := fmt.Sprintf("%s: %s", propertyArray[0], value)
props = append(props, propString)
}

Expand All @@ -271,7 +270,6 @@ func findAllNodesAndEdges(input interface{}) ([]models.NodeEntry, []models.EdgeE
*/
func queryGraphSlowlog(qm queryModel, client redisClient) backend.DataResponse {
response := backend.DataResponse{}

var result [][]string

// Run command
Expand Down Expand Up @@ -312,7 +310,6 @@ func queryGraphSlowlog(qm queryModel, client redisClient) backend.DataResponse {
*/
func queryGraphExplain(qm queryModel, client redisClient) backend.DataResponse {
response := backend.DataResponse{}

var result []string

// Run command
Expand Down Expand Up @@ -345,7 +342,6 @@ func queryGraphExplain(qm queryModel, client redisClient) backend.DataResponse {
*/
func queryGraphProfile(qm queryModel, client redisClient) backend.DataResponse {
response := backend.DataResponse{}

var result []string

// Run command
Expand Down Expand Up @@ -386,3 +382,30 @@ func queryGraphProfile(qm queryModel, client redisClient) backend.DataResponse {
// Return
return response
}

/**
* GRAPH.CONFIG <Graph name> {cypher}
*
* Retrieves or updates a RedisGraph configuration.
* @see https://oss.redislabs.com/redisgraph/commands/#graphconfig
*/
func queryGraphConfig(qm queryModel, client redisClient) backend.DataResponse {
response := backend.DataResponse{}
var result []interface{}

// Run command
err := client.RunFlatCmd(&result, qm.Command, "GET", "*")

// Check error
if err != nil {
return errorHandler(response, err)
}

// New Frame
frame := data.NewFrame(qm.Command)
frame = addFrameFieldsFromArray(result, frame)
response.Frames = append(response.Frames, frame)

// Return
return response
}
9 changes: 5 additions & 4 deletions pkg/redis-graph_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"testing"

"github.com/mediocregopher/radix/v3"
"github.com/redisgrafana/grafana-redis-datasource/pkg/models"
"github.com/stretchr/testify/require"
)

Expand All @@ -19,7 +20,7 @@ func TestGraphQueryIntegration(t *testing.T) {
client := radixV3Impl{radixClient: radixClient}

// Response
resp := queryGraphQuery(queryModel{Command: "graph.query", Key: "GOT_DEMO", Cypher: "MATCH (w:writer)-[r:wrote]->(b:book) return w,r,b"}, &client)
resp := queryGraphQuery(queryModel{Command: models.GraphQuery, Key: "GOT_DEMO", Cypher: "MATCH (w:writer)-[r:wrote]->(b:book) return w,r,b"}, &client)
require.Len(t, resp.Frames, 4)
require.Len(t, resp.Frames[0].Fields, 5)
require.Equal(t, "id", resp.Frames[0].Fields[0].Name)
Expand All @@ -42,7 +43,7 @@ func TestGraphQueryIntegrationWithoutRelations(t *testing.T) {
client := radixV3Impl{radixClient: radixClient}

// Response
resp := queryGraphQuery(queryModel{Command: "graph.query", Key: "GOT_DEMO", Cypher: "MATCH (w:writer)-[wrote]->(b:book) return w,b"}, &client)
resp := queryGraphQuery(queryModel{Command: models.GraphQuery, Key: "GOT_DEMO", Cypher: "MATCH (w:writer)-[wrote]->(b:book) return w,b"}, &client)
require.Len(t, resp.Frames, 3)
require.Len(t, resp.Frames[0].Fields, 5)
require.Equal(t, 15, resp.Frames[0].Fields[0].Len())
Expand All @@ -56,7 +57,7 @@ func TestGraphQueryIntegrationWithoutNodes(t *testing.T) {
client := radixV3Impl{radixClient: radixClient}

// Response
resp := queryGraphQuery(queryModel{Command: "graph.query", Key: "GOT_DEMO", Cypher: "MATCH (w:writer)-[r:wrote]->(b:book) return r"}, &client)
resp := queryGraphQuery(queryModel{Command: models.GraphQuery, Key: "GOT_DEMO", Cypher: "MATCH (w:writer)-[r:wrote]->(b:book) return r"}, &client)
require.Len(t, resp.Frames, 3)
require.Len(t, resp.Frames[0].Fields, 4)
require.Equal(t, 14, resp.Frames[0].Fields[0].Len())
Expand All @@ -73,7 +74,7 @@ func TestGraphSlowlogIntegration(t *testing.T) {
client := radixV3Impl{radixClient: radixClient}

// Response
resp := queryGraphSlowlog(queryModel{Command: "graph.slowlog", Key: "GOT_DEMO"}, &client)
resp := queryGraphSlowlog(queryModel{Command: models.GraphSlowlog, Key: "GOT_DEMO"}, &client)
require.Len(t, resp.Frames, 1)
require.Len(t, resp.Frames[0].Fields, 4)
}
71 changes: 61 additions & 10 deletions pkg/redis-graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"testing"
"time"

"github.com/redisgrafana/grafana-redis-datasource/pkg/models"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -195,7 +196,7 @@ func TestGraphQuery(t *testing.T) {
}

// Response
resp := queryGraphQuery(queryModel{Command: "graph.query", Key: "GOT_DEMO", Cypher: "MATCH (w:writer)-[r:wrote]->(b:book) return w,r,b"}, &client)
resp := queryGraphQuery(queryModel{Command: models.GraphQuery, Key: "GOT_DEMO", Cypher: "MATCH (w:writer)-[r:wrote]->(b:book) return w,r,b"}, &client)
require.Len(t, resp.Frames, 4)
require.Len(t, resp.Frames[0].Fields, 5)
require.Equal(t, "id", resp.Frames[0].Fields[0].Name)
Expand Down Expand Up @@ -266,7 +267,7 @@ func TestGraphQuery(t *testing.T) {
}

// Response
resp := queryGraphQuery(queryModel{Command: "graph.query", Key: "dungeon", Cypher: "MATCH (r:Room)-[:CONTAINS]->(t:Treasure) RETURN r.name, t.name, t.gp, t.float"}, &client)
resp := queryGraphQuery(queryModel{Command: models.GraphQuery, Key: "dungeon", Cypher: "MATCH (r:Room)-[:CONTAINS]->(t:Treasure) RETURN r.name, t.name, t.gp, t.float"}, &client)
require.Len(t, resp.Frames, 2)
require.Len(t, resp.Frames[0].Fields, 4)

Expand Down Expand Up @@ -312,7 +313,7 @@ func TestGraphQuery(t *testing.T) {
}

// Response
resp := queryGraphQuery(queryModel{Command: "graph.query", Key: "dungeon", Cypher: "MATCH (r:Room)-[:CONTAINS]->(t:Treasure) RETURN r.name, t.name, t.gp, t.float"}, &client)
resp := queryGraphQuery(queryModel{Command: models.GraphQuery, Key: "dungeon", Cypher: "MATCH (r:Room)-[:CONTAINS]->(t:Treasure) RETURN r.name, t.name, t.gp, t.float"}, &client)
require.Len(t, resp.Frames, 1)
require.Len(t, resp.Frames[0].Fields, 2)
})
Expand All @@ -330,7 +331,7 @@ func TestGraphQuery(t *testing.T) {
err: errors.New("error occurred")}

// Response
resp := queryGraphQuery(queryModel{Command: "graph.query", Key: "GOT_DEMO", Cypher: "MATCH (w:writer)-[r:wrote]->(b:book) return w,r,b"}, &client)
resp := queryGraphQuery(queryModel{Command: models.GraphQuery, Key: "GOT_DEMO", Cypher: "MATCH (w:writer)-[r:wrote]->(b:book) return w,r,b"}, &client)
require.EqualError(t, resp.Error, "error occurred")
})
}
Expand All @@ -356,7 +357,7 @@ func TestGraphSlowlog(t *testing.T) {
}

// Response
resp := queryGraphSlowlog(queryModel{Command: "graph.slowlog", Key: "GOT_DEMO"}, &client)
resp := queryGraphSlowlog(queryModel{Command: models.GraphSlowlog, Key: "GOT_DEMO"}, &client)
require.Len(t, resp.Frames, 1)
require.Len(t, resp.Frames[0].Fields, 4)
require.Equal(t, "timestamp", resp.Frames[0].Fields[0].Name)
Expand Down Expand Up @@ -385,7 +386,7 @@ func TestGraphSlowlog(t *testing.T) {
err: errors.New("error occurred")}

// Response
resp := queryGraphSlowlog(queryModel{Command: "graph.slowlog", Key: "GOT_DEMO"}, &client)
resp := queryGraphSlowlog(queryModel{Command: models.GraphSlowlog, Key: "GOT_DEMO"}, &client)
require.EqualError(t, resp.Error, "error occurred")
})
}
Expand All @@ -411,7 +412,7 @@ func TestGraphExplain(t *testing.T) {
}

// Response
resp := queryGraphExplain(queryModel{Command: "graph.explain", Key: "GOT_DEMO", Cypher: "MATCH (r:Room)-[:CONTAINS]->(t:Treasure) RETURN r.name, t.name, t.gp"}, &client)
resp := queryGraphExplain(queryModel{Command: models.GraphExplain, Key: "GOT_DEMO", Cypher: "MATCH (r:Room)-[:CONTAINS]->(t:Treasure) RETURN r.name, t.name, t.gp"}, &client)
require.Len(t, resp.Frames, 1)
require.Len(t, resp.Frames[0].Fields, 1)
require.Equal(t, "execution plan", resp.Frames[0].Fields[0].Name)
Expand All @@ -431,7 +432,7 @@ func TestGraphExplain(t *testing.T) {
err: errors.New("error occurred")}

// Response
resp := queryGraphExplain(queryModel{Command: "graph.explain", Key: "GOT_DEMO", Cypher: "MATCH (r:Room)-[:CONTAINS]->(t:Treasure) RETURN r.name, t.name, t.gp"}, &client)
resp := queryGraphExplain(queryModel{Command: models.GraphExplain, Key: "GOT_DEMO", Cypher: "MATCH (r:Room)-[:CONTAINS]->(t:Treasure) RETURN r.name, t.name, t.gp"}, &client)
require.EqualError(t, resp.Error, "error occurred")
})
}
Expand Down Expand Up @@ -460,7 +461,7 @@ func TestGraphProfile(t *testing.T) {
}

// Response
resp := queryGraphProfile(queryModel{Command: "graph.profile", Key: "GOT_DEMO", Cypher: "MATCH (r:Room)-[:CONTAINS]->(t:Treasure) RETURN r.name, t.name, t.gp"}, &client)
resp := queryGraphProfile(queryModel{Command: models.GraphProfile, Key: "GOT_DEMO", Cypher: "MATCH (r:Room)-[:CONTAINS]->(t:Treasure) RETURN r.name, t.name, t.gp"}, &client)
require.Len(t, resp.Frames, 1)
require.Len(t, resp.Frames[0].Fields, 3)
require.Equal(t, "operation", resp.Frames[0].Fields[0].Name)
Expand All @@ -485,7 +486,57 @@ func TestGraphProfile(t *testing.T) {
err: errors.New("error occurred")}

// Response
resp := queryGraphProfile(queryModel{Command: "graph.explain", Key: "GOT_DEMO", Cypher: "MATCH (r:Room)-[:CONTAINS]->(t:Treasure) RETURN r.name, t.name, t.gp"}, &client)
resp := queryGraphProfile(queryModel{Command: models.GraphProfile, Key: "GOT_DEMO", Cypher: "MATCH (r:Room)-[:CONTAINS]->(t:Treasure) RETURN r.name, t.name, t.gp"}, &client)
require.EqualError(t, resp.Error, "error occurred")
})
}

/**
* GRAPH.CONFIG
*/
func TestGraphConfig(t *testing.T) {
t.Parallel()

/**
* Success
*/
t.Run("should process command", func(t *testing.T) {
t.Parallel()

// Client
client := testClient{
rcv: []interface{}{
[]interface{}{[]byte("CACHE_SIZE"), int64(25)},
[]interface{}{[]byte("ASYNC_DELETE"), int64(1)},
[]interface{}{[]byte("THREAD_COUNT"), float64(3.14)},
},
err: nil,
}

// Response
resp := queryGraphConfig(queryModel{Command: models.GraphConfig}, &client)
require.Len(t, resp.Frames, 1)
require.Len(t, resp.Frames[0].Fields, 3)
require.Equal(t, "CACHE_SIZE", resp.Frames[0].Fields[0].Name)
require.Equal(t, int64(25), resp.Frames[0].Fields[0].At(0))
require.Equal(t, "THREAD_COUNT", resp.Frames[0].Fields[2].Name)
require.Equal(t, float64(3.14), resp.Frames[0].Fields[2].At(0))
})

/**
* Error
*/
t.Run("should handle error", func(t *testing.T) {
t.Parallel()

// Client
client := testClient{
rcv: nil,
batchRcv: nil,
err: errors.New("error occurred")}

// Response
resp := queryGraphConfig(queryModel{Command: models.GraphConfig}, &client)
require.EqualError(t, resp.Error, "error occurred")
})
}
Loading

0 comments on commit 8946bed

Please sign in to comment.