Skip to content

Commit e6fc6a6

Browse files
Add optional timeout argument to graph queries (#31)
* Add Query endpoints with QueryOptions support * Use getter/setter framework for QueryOptions * Address PR comments * Update documentation
1 parent f906451 commit e6fc6a6

File tree

3 files changed

+93
-1
lines changed

3 files changed

+93
-1
lines changed

README.md

+11
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,17 @@ Name: John Doe
123123
Age: 33
124124
```
125125

126+
## Running queries with timeouts
127+
128+
Queries can be run with a millisecond-level timeout as described in [the module documentation](https://oss.redis.com/redisgraph/configuration/#timeout). To take advantage of this feature, the `QueryOptions` struct should be used:
129+
130+
```go
131+
options := NewQueryOptions().SetTimeout(10) // 10-millisecond timeout
132+
res, err := graph.QueryWithOptions("MATCH (src {name: 'John Doe'})-[*]->(dest) RETURN dest", options)
133+
```
134+
135+
`ParameterizedQueryWithOptions` and `ROQueryWithOptions` endpoints are also exposed by the client.
136+
126137
## Running tests
127138

128139
A simple test suite is provided, and can be run with:

client_test.go

+19
Original file line numberDiff line numberDiff line change
@@ -473,3 +473,22 @@ func TestNodeMapDatatype(t *testing.T) {
473473
assert.Nil(t, err)
474474
assert.Equal(t, 1, res.RelationshipsDeleted(), "Expecting 1 relationships deleted")
475475
}
476+
477+
func TestTimeout(t *testing.T) {
478+
// Instantiate a new QueryOptions struct with a 1-second timeout
479+
options := NewQueryOptions().SetTimeout(1)
480+
481+
// Verify that the timeout was set properly
482+
assert.Equal(t, 1, options.GetTimeout())
483+
484+
// Issue a long-running query with a 1-millisecond timeout.
485+
res, err := graph.QueryWithOptions("UNWIND range(0, 1000000) AS v RETURN v", options)
486+
assert.Nil(t, res)
487+
assert.NotNil(t, err)
488+
489+
params := make(map[string]interface{})
490+
params["ub"] = 1000000
491+
res, err = graph.ParameterizedQueryWithOptions("UNWIND range(0, $ub) AS v RETURN v", params, options);
492+
assert.Nil(t, res)
493+
assert.NotNil(t, err)
494+
}

graph.go

+63-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ import (
88
"github.com/gomodule/redigo/redis"
99
)
1010

11+
// QueryOptions are a set of additional arguments to be emitted with a query.
12+
type QueryOptions struct {
13+
timeout int
14+
}
15+
1116
// Graph represents a graph, which is a collection of nodes and edges.
1217
type Graph struct {
1318
Id string
@@ -97,9 +102,26 @@ func (g *Graph) Commit() (*QueryResult, error) {
97102
return g.Query(q)
98103
}
99104

105+
// NewQueryOptions instantiates a new QueryOptions struct.
106+
func NewQueryOptions() *QueryOptions {
107+
return &QueryOptions{
108+
timeout: -1,
109+
}
110+
}
111+
112+
// SetTimeout sets the timeout member of the QueryOptions struct
113+
func (options *QueryOptions) SetTimeout(timeout int) *QueryOptions {
114+
options.timeout = timeout
115+
return options
116+
}
117+
118+
// GetTimeout retrieves the timeout of the QueryOptions struct
119+
func (options *QueryOptions) GetTimeout() int {
120+
return options.timeout
121+
}
122+
100123
// Query executes a query against the graph.
101124
func (g *Graph) Query(q string) (*QueryResult, error) {
102-
103125
r, err := g.Conn.Do("GRAPH.QUERY", g.Id, q, "--compact")
104126
if err != nil {
105127
return nil, err
@@ -126,6 +148,46 @@ func (g *Graph) ParameterizedQuery(q string, params map[string]interface{}) (*Qu
126148
return g.Query(q);
127149
}
128150

151+
// QueryWithOptions issues a query with the given timeout
152+
func (g *Graph) QueryWithOptions(q string, options *QueryOptions) (*QueryResult, error) {
153+
var r interface{}
154+
var err error
155+
if(options.timeout >= 0) {
156+
r, err = g.Conn.Do("GRAPH.QUERY", g.Id, q, "--compact", "timeout", options.timeout)
157+
} else {
158+
r, err = g.Conn.Do("GRAPH.QUERY", g.Id, q, "--compact")
159+
}
160+
if err != nil {
161+
return nil, err
162+
}
163+
164+
return QueryResultNew(g, r)
165+
}
166+
167+
// ParameterizedQueryWithOptions issues a parameterized query with the given timeout
168+
func (g *Graph) ParameterizedQueryWithOptions(q string, params map[string]interface{}, options *QueryOptions) (*QueryResult, error) {
169+
if(params != nil){
170+
q = BuildParamsHeader(params) + q
171+
}
172+
return g.QueryWithOptions(q, options);
173+
}
174+
175+
// ROQueryWithOptions issues a read-only query with the given timeout
176+
func (g *Graph) ROQueryWithOptions(q string, options *QueryOptions) (*QueryResult, error) {
177+
var r interface{}
178+
var err error
179+
if(options.timeout >= 0) {
180+
r, err = g.Conn.Do("GRAPH.RO_QUERY", g.Id, q, "--compact", "timeout", options.timeout)
181+
} else {
182+
r, err = g.Conn.Do("GRAPH.RO_QUERY", g.Id, q, "--compact")
183+
}
184+
if err != nil {
185+
return nil, err
186+
}
187+
188+
return QueryResultNew(g, r)
189+
}
190+
129191
// Merge pattern
130192
func (g *Graph) Merge(p string) (*QueryResult, error) {
131193
q := fmt.Sprintf("MERGE %s", p)

0 commit comments

Comments
 (0)