redis/graph.go

205 lines
4.8 KiB
Go
Raw Normal View History

package redis
import (
"context"
"strconv"
)
type GraphCmdable interface {
GraphQuery(ctx context.Context, key, query string) *GraphCmd
}
// GraphQuery executes a query on a graph, exec: GRAPH.QUERY key query
func (c cmdable) GraphQuery(ctx context.Context, key, query string) *GraphCmd {
cmd := NewGraphCmd(ctx, "GRAPH.QUERY", key, query)
_ = c(ctx, cmd)
return cmd
}
// ----------------------------------------------------------------------------
type GraphValue interface {
IsNil() bool
String() string
Int() int
Bool() bool
Float64() float64
Node() (*GraphNode, bool)
Edge() (*GraphEdge, bool)
}
type (
graphDataType int
graphRowType int
)
const (
graphInteger graphDataType = iota + 1 // int (graph int)
graphNil // nil (graph nil/null)
graphString // string (graph string/boolean/double)
)
const (
graphResultBasic graphRowType = iota + 1 // int/nil/string
graphResultNode // node(3), id +labels +properties
graphResultEdge // edge(5), id + type + src_node + dest_node + properties
)
type GraphResult struct {
noResult bool
text []string
field []string
rows [][]*graphRow
err error
}
// Message is used to obtain statistical information about the execution of graph statements.
func (g *GraphResult) Message() []string {
return g.text
}
// IsResult indicates whether the statement has a result set response.
// For example, a MATCH statement always has a result set (regardless of the number of rows in the response),
// while a CREATE statement does not.
func (g *GraphResult) IsResult() bool {
return !g.noResult
}
// Error return exec error
func (g *GraphResult) Error() error {
return g.err
}
// Field returns the fields in the query result set.
// If the statement has no result set (IsResult() == false), it returns nil.
func (g *GraphResult) Field() []string {
return g.field
}
// Len return the number of rows in the result set.
func (g *GraphResult) Len() int {
return len(g.rows)
}
// Row read the first row of data in the result set. If there is no data response, return redis.Nil.
func (g *GraphResult) Row() (map[string]GraphValue, error) {
if g.err != nil {
return nil, g.err
}
if g.noResult || len(g.field) == 0 || len(g.rows) == 0 || len(g.rows[0]) == 0 {
return nil, Nil
}
row := make(map[string]GraphValue, len(g.field))
for i, f := range g.field {
row[f] = g.rows[0][i]
}
return row, nil
}
// Rows return all result set responses, If there is no data response, return redis.Nil.
func (g *GraphResult) Rows() ([]map[string]GraphValue, error) {
if g.err != nil {
return nil, g.err
}
if g.noResult || len(g.field) == 0 || len(g.rows) == 0 || len(g.rows[0]) == 0 {
return nil, Nil
}
rows := make([]map[string]GraphValue, 0, len(g.rows))
for i := 0; i < len(g.rows); i++ {
row := make(map[string]GraphValue, len(g.field))
for x, f := range g.field {
row[f] = g.rows[i][x]
}
rows = append(rows, row)
}
return rows, nil
}
type graphRow struct {
typ graphRowType
basic GraphData
node GraphNode
edge GraphEdge
}
func (g *graphRow) IsNil() bool { return g.basic.IsNil() }
func (g *graphRow) String() string { return g.basic.String() }
func (g *graphRow) Int() int { return g.basic.Int() }
func (g *graphRow) Bool() bool { return g.basic.Bool() }
func (g *graphRow) Float64() float64 { return g.basic.Float64() }
func (g *graphRow) Node() (*GraphNode, bool) { return &g.node, g.typ == graphResultNode }
func (g *graphRow) Edge() (*GraphEdge, bool) { return &g.edge, g.typ == graphResultEdge }
type GraphData struct {
typ graphDataType
integerVal int64
stringVal string
}
func (d GraphData) IsNil() bool {
return d.typ == graphNil
}
func (d GraphData) String() string {
switch d.typ {
case graphInteger:
return strconv.FormatInt(d.integerVal, 10)
case graphNil:
return ""
case graphString:
return d.stringVal
default:
return ""
}
}
func (d GraphData) Int() int {
switch d.typ {
case graphInteger:
return int(d.integerVal)
case graphString:
n, _ := strconv.Atoi(d.stringVal)
return n
default:
return 0
}
}
func (d GraphData) Bool() bool {
switch d.typ {
case graphInteger:
return d.integerVal != 0
case graphNil:
return false
case graphString:
return d.stringVal == "true"
default:
return false
}
}
func (d GraphData) Float64() float64 {
if d.typ == graphInteger {
return float64(d.integerVal)
}
if d.typ == graphString {
v, _ := strconv.ParseFloat(d.stringVal, 64)
return v
}
return 0
}
type GraphNode struct {
ID int64
Labels []string
Properties map[string]GraphData
}
type GraphEdge struct {
ID int64
Typ string
SrcNode int64
DstNode int64
Properties map[string]GraphData
}