redisgraph 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +7 -0
- data/LICENSE +29 -0
- data/README.md +44 -0
- data/lib/redisgraph/connection.rb +16 -0
- data/lib/redisgraph/errors.rb +10 -0
- data/lib/redisgraph/query_result.rb +59 -0
- data/lib/redisgraph/version.rb +3 -0
- data/lib/redisgraph.rb +44 -0
- data/redisgraph.gemspec +24 -0
- data/test/test_suite.rb +89 -0
- metadata +88 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cbcd7f55a9dd3006c0f4a050171da9987e753f75fd20a99a9e22a1a7094c370b
|
4
|
+
data.tar.gz: 3b0094755a897bb7d8c8ddaed7a97ac741efb59cbd36983d67caa5a743142b3b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 22b67bea86caecf0c5dc9822a96395f452d3043dc79975b6c6c0e05d02cdb0e7523d65500f5c3ce4bacd56f7b81b25a556c50707db25c02e5bab007ead7dae34
|
7
|
+
data.tar.gz: 8152ef37023f1ecc2dc3bf4688c3a4e21b3a56bad16af9dcdfaaf11f2f671fe754cedcd81b9d68d9e62f01643535d5594dad52750f947d870676dfe51431e44f
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
BSD 3-Clause License
|
2
|
+
|
3
|
+
Copyright (c) 2018, Redis Labs
|
4
|
+
All rights reserved.
|
5
|
+
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
8
|
+
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this
|
10
|
+
list of conditions and the following disclaimer.
|
11
|
+
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
14
|
+
and/or other materials provided with the distribution.
|
15
|
+
|
16
|
+
* Neither the name of the copyright holder nor the names of its
|
17
|
+
contributors may be used to endorse or promote products derived from
|
18
|
+
this software without specific prior written permission.
|
19
|
+
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# redisgraph-rb
|
2
|
+
|
3
|
+
`redisgraph-rb` is a Ruby gem client for the RedisGraph module. It relies on `redis-rb` for Redis connection management and provides support for graph QUERY, EXPLAIN, and DELETE commands.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
```
|
7
|
+
require 'redisgraph'
|
8
|
+
|
9
|
+
graphname = "sample"
|
10
|
+
|
11
|
+
r = RedisGraph.new(graphname)
|
12
|
+
|
13
|
+
cmd = """CREATE (:person {name: 'Jim', age: 29})-[:works]->(:employer {name: 'Dunder Mifflin'})"""
|
14
|
+
response = r.query(cmd)
|
15
|
+
response.stats
|
16
|
+
=> {:labels_added=>2, :nodes_created=>2, :properties_set=>3, :relationships_created=>1, :internal_execution_time=>0.705541}
|
17
|
+
|
18
|
+
cmd = """MATCH ()-[:works]->(e:employer) RETURN e"""
|
19
|
+
|
20
|
+
response = r.query(cmd)
|
21
|
+
|
22
|
+
response.print_resultset
|
23
|
+
+----------------+
|
24
|
+
| e.name |
|
25
|
+
+----------------+
|
26
|
+
| Dunder Mifflin |
|
27
|
+
+----------------+
|
28
|
+
|
29
|
+
r.delete
|
30
|
+
=> "Graph removed, internal execution time: 0.416024 milliseconds"
|
31
|
+
```
|
32
|
+
|
33
|
+
## Specifying Redis options
|
34
|
+
RedisGraph connects to an active Redis server, defaulting to `host: localhost, port: 6379`. To provide custom connection parameters, instantiate a RedisGraph object with a `redis_options` hash:
|
35
|
+
|
36
|
+
`r = RedisGraph.new("graphname", redis_options= { host: "127.0.0.1", port: 26380 })`
|
37
|
+
|
38
|
+
These parameters are described fully in the documentation for https://github.com/redis/redis-rb
|
39
|
+
|
40
|
+
## Running tests
|
41
|
+
A simple test suite is provided, and can be run with:
|
42
|
+
`ruby test/test_suite.rb`
|
43
|
+
These tests expect a Redis server with the Graph module loaded to be available at localhost:6379
|
44
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class RedisGraph
|
2
|
+
def connect_to_server(options)
|
3
|
+
@connection = Redis.new(options)
|
4
|
+
self.verify_module()
|
5
|
+
end
|
6
|
+
|
7
|
+
# Ensure that the connected Redis server supports modules
|
8
|
+
# and has loaded the RedisGraph module
|
9
|
+
def verify_module()
|
10
|
+
redis_version = @connection.info["redis_version"]
|
11
|
+
major_version = redis_version.split('.').first.to_i
|
12
|
+
raise ServerError, "Redis 4.0 or greater required for RedisGraph support." unless major_version >= 4
|
13
|
+
resp = @connection.call("MODULE", "LIST")
|
14
|
+
raise ServerError, "RedisGraph module not loaded." unless resp.first && resp.first.include?("graph")
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
class QueryResult
|
2
|
+
attr_accessor :columns
|
3
|
+
attr_accessor :resultset
|
4
|
+
attr_accessor :stats
|
5
|
+
|
6
|
+
def print_resultset
|
7
|
+
pretty = Terminal::Table.new headings: columns do |t|
|
8
|
+
resultset.each { |record| t << record }
|
9
|
+
end
|
10
|
+
puts pretty
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_resultset(response)
|
14
|
+
# Any non-empty result set will have multiple rows (arrays)
|
15
|
+
return nil unless response[0].length > 1
|
16
|
+
# First row is return elements / properties
|
17
|
+
@columns = response[0].shift
|
18
|
+
# Subsequent rows are records
|
19
|
+
@resultset = response[0]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Read metrics about internal query handling
|
23
|
+
def parse_stats(response)
|
24
|
+
return nil unless response[1]
|
25
|
+
|
26
|
+
stats = {}
|
27
|
+
|
28
|
+
response[1].each do |stat|
|
29
|
+
line = stat.split(': ')
|
30
|
+
val = line[1].split(' ')[0]
|
31
|
+
|
32
|
+
case line[0]
|
33
|
+
when /^Labels added/
|
34
|
+
stats[:labels_added] = val.to_i
|
35
|
+
when /^Nodes created/
|
36
|
+
stats[:nodes_created] = val.to_i
|
37
|
+
when /^Nodes deleted/
|
38
|
+
stats[:nodes_deleted] = val.to_i
|
39
|
+
when /^Relationships deleted/
|
40
|
+
stats[:relationships_deleted] = val.to_i
|
41
|
+
when /^Properties set/
|
42
|
+
stats[:properties_set] = val.to_i
|
43
|
+
when /^Relationships created/
|
44
|
+
stats[:relationships_created] = val.to_i
|
45
|
+
when /^Query internal execution time/
|
46
|
+
stats[:internal_execution_time] = val.to_f
|
47
|
+
end
|
48
|
+
end
|
49
|
+
stats
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize(response)
|
53
|
+
# The response for any query is expected to be a nested array.
|
54
|
+
# The only top-level values will be the result set and the statistics.
|
55
|
+
@resultset = parse_resultset(response)
|
56
|
+
@stats = parse_stats(response)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
data/lib/redisgraph.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'redis'
|
2
|
+
require 'terminal-table'
|
3
|
+
|
4
|
+
require_relative 'redisgraph/errors.rb'
|
5
|
+
require_relative 'redisgraph/query_result.rb'
|
6
|
+
require_relative 'redisgraph/connection.rb'
|
7
|
+
|
8
|
+
class RedisGraph
|
9
|
+
attr_accessor :connection
|
10
|
+
attr_accessor :graphname
|
11
|
+
|
12
|
+
# The RedisGraph constructor instantiates a Redis connection
|
13
|
+
# and validates that the graph module is loaded
|
14
|
+
def initialize(graph, redis_options = {})
|
15
|
+
@graphname = graph
|
16
|
+
connect_to_server(redis_options)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Execute a command and return its parsed result
|
20
|
+
def query(command)
|
21
|
+
begin
|
22
|
+
resp = @connection.call("GRAPH.QUERY", @graphname, command)
|
23
|
+
rescue Redis::CommandError => e
|
24
|
+
raise QueryError, e
|
25
|
+
end
|
26
|
+
|
27
|
+
QueryResult.new(resp)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return the execution plan for a given command
|
31
|
+
def explain(command)
|
32
|
+
begin
|
33
|
+
resp = @connection.call("GRAPH.EXPLAIN", @graphname, command)
|
34
|
+
rescue Redis::CommandError => e
|
35
|
+
raise QueryError, e
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Delete the graph and all associated keys
|
40
|
+
def delete
|
41
|
+
resp = @connection.call("GRAPH.DELETE", @graphname)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
data/redisgraph.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "./lib/redisgraph/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "redisgraph"
|
5
|
+
|
6
|
+
s.version = RedisGraph::VERSION
|
7
|
+
|
8
|
+
s.license = 'BSD-3-Clause'
|
9
|
+
|
10
|
+
s.homepage = 'https://github.com/redislabs/redisgraph-rb'
|
11
|
+
|
12
|
+
s.summary = 'A client for RedisGraph'
|
13
|
+
|
14
|
+
s.description = 'A client that extends redis-rb to provide explicit support for the RedisGraph module.'
|
15
|
+
|
16
|
+
s.authors = ['Redis Labs']
|
17
|
+
|
18
|
+
s.email = 'jeffrey@redislabs.com'
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
|
22
|
+
s.add_runtime_dependency('redis', '~> 4')
|
23
|
+
s.add_runtime_dependency('terminal-table', '~> 1', '>= 1.8')
|
24
|
+
end
|
data/test/test_suite.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require_relative '../lib/redisgraph.rb'
|
2
|
+
require "test/unit"
|
3
|
+
include Test::Unit::Assertions
|
4
|
+
|
5
|
+
# Helper functions
|
6
|
+
# TODO it would be nice to have something like DisposableRedis
|
7
|
+
|
8
|
+
# Connect to a Redis server on localhost:6379
|
9
|
+
def connect_test
|
10
|
+
begin
|
11
|
+
@r = RedisGraph.new("rubytest")
|
12
|
+
rescue Redis::BaseError => e
|
13
|
+
puts e
|
14
|
+
puts "RedisGraph tests require that a Redis server with the graph module loaded be running on localhost:6379"
|
15
|
+
exit 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Ensure that the graph "rubytest" does not exist
|
20
|
+
def delete_graph
|
21
|
+
@r.delete
|
22
|
+
end
|
23
|
+
|
24
|
+
# Test functions - each validates one or more EXPLAIN and QUERY calls
|
25
|
+
|
26
|
+
def validate_node_creation
|
27
|
+
query_str = """CREATE (t:node {name: 'src'})"""
|
28
|
+
x = @r.query(query_str)
|
29
|
+
plan = @r.explain(query_str)
|
30
|
+
assert(plan =~ /Create/)
|
31
|
+
assert(x.resultset.nil?)
|
32
|
+
assert(x.stats[:labels_added] == 1)
|
33
|
+
assert(x.stats[:nodes_created] == 1)
|
34
|
+
assert(x.stats[:properties_set] == 1)
|
35
|
+
puts "Create node - PASSED"
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate_node_deletion
|
39
|
+
query_str = """MATCH (t:node) WHERE t.name = 'src' DELETE t"""
|
40
|
+
plan = @r.explain(query_str)
|
41
|
+
assert(plan =~ /Delete/)
|
42
|
+
x = @r.query(query_str)
|
43
|
+
assert(x.resultset.nil?)
|
44
|
+
assert(x.stats[:nodes_deleted] == 1)
|
45
|
+
query_str = """MATCH (t:node) WHERE t.name = 'src' RETURN t"""
|
46
|
+
assert(x.resultset.nil?)
|
47
|
+
puts "Delete node - PASSED"
|
48
|
+
end
|
49
|
+
|
50
|
+
def validate_edge_creation
|
51
|
+
query_str = """CREATE (p:node {name: 'src1'})-[:edge]->(:node {name: 'dest1'}), (:node {name: 'src2'})-[:edge]->(q:node_type_2 {name: 'dest2'})"""
|
52
|
+
plan = @r.explain(query_str)
|
53
|
+
assert(plan =~ /Create/)
|
54
|
+
x = @r.query(query_str)
|
55
|
+
assert(x.resultset.nil?)
|
56
|
+
assert(x.stats[:nodes_created] == 4)
|
57
|
+
assert(x.stats[:properties_set] == 4)
|
58
|
+
assert(x.stats[:relationships_created] == 2)
|
59
|
+
puts "Add edges - PASSED"
|
60
|
+
end
|
61
|
+
|
62
|
+
def validate_edge_traversal
|
63
|
+
query_str = """MATCH (a)-[:edge]->(b:node) RETURN a, b"""
|
64
|
+
plan = @r.explain(query_str)
|
65
|
+
assert(plan.include?("Traverse"))
|
66
|
+
x = @r.query(query_str)
|
67
|
+
assert(x.resultset)
|
68
|
+
assert(x.columns.length == 2)
|
69
|
+
assert(x.resultset.length == 1)
|
70
|
+
assert(x.resultset[0] == ["src1", "dest1"])
|
71
|
+
puts "Traverse edge - PASSED"
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_suite
|
75
|
+
puts "Running RedisGraph tests..."
|
76
|
+
connect_test
|
77
|
+
delete_graph # Clear the graph
|
78
|
+
|
79
|
+
# Test basic functionalities
|
80
|
+
validate_node_creation
|
81
|
+
validate_node_deletion
|
82
|
+
validate_edge_creation
|
83
|
+
validate_edge_traversal
|
84
|
+
|
85
|
+
delete_graph # Clear the graph again
|
86
|
+
puts "RedisGraph tests passed!"
|
87
|
+
end
|
88
|
+
|
89
|
+
test_suite
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redisgraph
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Redis Labs
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-08-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: redis
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: terminal-table
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1'
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '1.8'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1'
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.8'
|
47
|
+
description: A client that extends redis-rb to provide explicit support for the RedisGraph
|
48
|
+
module.
|
49
|
+
email: jeffrey@redislabs.com
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- Gemfile
|
55
|
+
- LICENSE
|
56
|
+
- README.md
|
57
|
+
- lib/redisgraph.rb
|
58
|
+
- lib/redisgraph/connection.rb
|
59
|
+
- lib/redisgraph/errors.rb
|
60
|
+
- lib/redisgraph/query_result.rb
|
61
|
+
- lib/redisgraph/version.rb
|
62
|
+
- redisgraph.gemspec
|
63
|
+
- test/test_suite.rb
|
64
|
+
homepage: https://github.com/redislabs/redisgraph-rb
|
65
|
+
licenses:
|
66
|
+
- BSD-3-Clause
|
67
|
+
metadata: {}
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 2.7.7
|
85
|
+
signing_key:
|
86
|
+
specification_version: 4
|
87
|
+
summary: A client for RedisGraph
|
88
|
+
test_files: []
|