redgraph 0.1.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/.github/workflows/main.yml +18 -0
- data/.gitignore +8 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +29 -0
- data/LICENSE.txt +21 -0
- data/README.md +73 -0
- data/Rakefile +12 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/lib/redgraph.rb +13 -0
- data/lib/redgraph/edge.rb +18 -0
- data/lib/redgraph/graph.rb +140 -0
- data/lib/redgraph/node.rb +20 -0
- data/lib/redgraph/query_response.rb +72 -0
- data/lib/redgraph/version.rb +5 -0
- data/redgraph.gemspec +26 -0
- data/test/graph_connection_test.rb +11 -0
- data/test/graph_manipulation_test.rb +32 -0
- data/test/graph_queries_test.rb +58 -0
- data/test/graph_test.rb +56 -0
- data/test/redgraph_test.rb +9 -0
- data/test/test_helper.rb +12 -0
- metadata +83 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 80c7cce1d1d19897882873e07e7a5a1fadabbb52d14717e16ff113f83511b32a
|
4
|
+
data.tar.gz: 72be15f7b95a7b45ec9ec21adb54f54676e0f960938c602fbb8381ae3ca1c682
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cce480b50ada0fb75bb1491d730668a8ac7f92be766dd161b1b3c3fa8082d579d7276383adb2966894388f6c95fb7e444abd9eb2935e50f6659d35be938df450
|
7
|
+
data.tar.gz: 806e2105e78b9c6a188dd271ed7b6315ec9afbe0bbd6d1008eb2c4f991e756512e7b4a83dbb7808b944ab2c8b66671f270cb1a4008a476945c9f20818209dad9
|
@@ -0,0 +1,18 @@
|
|
1
|
+
name: Ruby
|
2
|
+
|
3
|
+
on: [push,pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
steps:
|
9
|
+
- uses: actions/checkout@v2
|
10
|
+
- name: Set up Ruby
|
11
|
+
uses: ruby/setup-ruby@v1
|
12
|
+
with:
|
13
|
+
ruby-version: 3.0.0
|
14
|
+
- name: Run the default task
|
15
|
+
run: |
|
16
|
+
gem install bundler -v 2.2.15
|
17
|
+
bundle install
|
18
|
+
bundle exec rake
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
redgraph (0.1.0)
|
5
|
+
redis (~> 4)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
coderay (1.1.3)
|
11
|
+
method_source (1.0.0)
|
12
|
+
minitest (5.14.4)
|
13
|
+
pry (0.14.0)
|
14
|
+
coderay (~> 1.1)
|
15
|
+
method_source (~> 1.0)
|
16
|
+
rake (13.0.3)
|
17
|
+
redis (4.2.5)
|
18
|
+
|
19
|
+
PLATFORMS
|
20
|
+
x86_64-darwin-20
|
21
|
+
|
22
|
+
DEPENDENCIES
|
23
|
+
minitest (~> 5.0)
|
24
|
+
pry (~> 0.14.0)
|
25
|
+
rake (~> 13.0)
|
26
|
+
redgraph!
|
27
|
+
|
28
|
+
BUNDLED WITH
|
29
|
+
2.2.15
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2021 Paolo Zaccagnini
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# Redgraph
|
2
|
+
|
3
|
+
A simple RedisGraph library. This gem owes **a lot** to the existing [redisgraph-rb](https://github.com/RedisGraph/redisgraph-rb) gem, but tries to provide a friendlier interface, similar to the existing [Python](https://github.com/RedisGraph/redisgraph-py) and [Elixir](https://github.com/crflynn/redisgraph-ex) clients.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'redgraph'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle install
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install redgraph
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Basic usage:
|
24
|
+
|
25
|
+
graph = Redgraph::Graph.new('movies', url: "redis://localhost:6379/1")
|
26
|
+
|
27
|
+
Create a couple nodes:
|
28
|
+
|
29
|
+
actor = Redgraph::Node.new(label: 'actor', attributes: {name: "Al Pacino"})
|
30
|
+
graph.add_node(actor)
|
31
|
+
film = Redgraph::Node.new(label: 'film', attributes: {name: "Scarface"})
|
32
|
+
graph.add_node(film)
|
33
|
+
|
34
|
+
Create an edge between those nodes:
|
35
|
+
|
36
|
+
edge = Redgraph::Edge.new(src: actor, dest: film, type: 'ACTOR_IN', properties: {role: "Tony Montana"})
|
37
|
+
result = @graph.add_edge(edge)
|
38
|
+
|
39
|
+
Find a node by id:
|
40
|
+
|
41
|
+
@graph.find_node_by_id(123)
|
42
|
+
|
43
|
+
To get all nodes:
|
44
|
+
|
45
|
+
@graph.nodes
|
46
|
+
|
47
|
+
Optional filters:
|
48
|
+
|
49
|
+
@graph.nodes(label: 'actor')
|
50
|
+
|
51
|
+
## Development
|
52
|
+
|
53
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
54
|
+
|
55
|
+
TEST_REDIS_URL=YOUR-REDIS-URL rake test
|
56
|
+
|
57
|
+
to run the tests.
|
58
|
+
|
59
|
+
You can use a `TEST_REDIS_URL` such as `redis://localhost:6379/1`. Make sure you're not overwriting important databases.
|
60
|
+
|
61
|
+
You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
62
|
+
|
63
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
64
|
+
|
65
|
+
Run `bin/console` for an interactive prompt.
|
66
|
+
|
67
|
+
## Contributing
|
68
|
+
|
69
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/pzac/redgraph.
|
70
|
+
|
71
|
+
## License
|
72
|
+
|
73
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "redgraph"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
require "pry"
|
11
|
+
Pry.start
|
data/bin/setup
ADDED
data/lib/redgraph.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "redis"
|
3
|
+
|
4
|
+
require_relative "redgraph/version"
|
5
|
+
require_relative "redgraph/graph"
|
6
|
+
require_relative "redgraph/node"
|
7
|
+
require_relative "redgraph/edge"
|
8
|
+
require_relative "redgraph/query_response"
|
9
|
+
|
10
|
+
module Redgraph
|
11
|
+
class Error < StandardError; end
|
12
|
+
class ServerError < Error; end
|
13
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Redgraph
|
4
|
+
class Edge
|
5
|
+
attr_accessor :id, :src, :dest, :type, :properties
|
6
|
+
|
7
|
+
def initialize(src:, dest:, type:, properties: {})
|
8
|
+
@src = src
|
9
|
+
@dest = dest
|
10
|
+
@type = type
|
11
|
+
@properties = properties
|
12
|
+
end
|
13
|
+
|
14
|
+
def persisted?
|
15
|
+
!id.nil?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Redgraph
|
4
|
+
class Graph
|
5
|
+
attr_accessor :connection, :graph_name
|
6
|
+
|
7
|
+
def initialize(graph, redis_options = {})
|
8
|
+
@graph_name = graph
|
9
|
+
@connection = Redis.new(redis_options)
|
10
|
+
@module_version = module_version
|
11
|
+
raise ServerError unless @module_version
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns the version of the RedisGraph module
|
15
|
+
#
|
16
|
+
def module_version
|
17
|
+
modules = @connection.call("MODULE", "LIST")
|
18
|
+
module_graph = modules.detect { |_, name, _, version| name == 'graph' }
|
19
|
+
module_graph[3] if module_graph
|
20
|
+
end
|
21
|
+
|
22
|
+
# Deletes an existing graph
|
23
|
+
#
|
24
|
+
def delete
|
25
|
+
@connection.call("GRAPH.DELETE", graph_name)
|
26
|
+
rescue Redis::CommandError => e
|
27
|
+
# Catch exception if the graph was already deleted
|
28
|
+
return nil if e.message =~ /ERR Invalid graph operation on empty key/
|
29
|
+
raise e
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns an array of existing graphs
|
33
|
+
#
|
34
|
+
def list
|
35
|
+
@connection.call("GRAPH.LIST")
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns an array of existing labels
|
39
|
+
#
|
40
|
+
def labels
|
41
|
+
result = query("CALL db.labels()")
|
42
|
+
result.resultset.map(&:values).flatten
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns an array of existing properties
|
46
|
+
#
|
47
|
+
def properties
|
48
|
+
result = query("CALL db.propertyKeys()")
|
49
|
+
result.resultset.map(&:values).flatten
|
50
|
+
end
|
51
|
+
|
52
|
+
# Adds a node. If successul it returns the created object, otherwise false
|
53
|
+
#
|
54
|
+
def add_node(node)
|
55
|
+
result = query("CREATE (n:`#{node.label}` #{quote_hash(node.properties)}) RETURN ID(n)")
|
56
|
+
return false if result.stats[:nodes_created] != 1
|
57
|
+
id = result.resultset.first["ID(n)"]
|
58
|
+
node.id = id
|
59
|
+
node
|
60
|
+
end
|
61
|
+
|
62
|
+
def find_node_by_id(id)
|
63
|
+
result = query("MATCH (node) WHERE ID(node) = #{id} RETURN node")
|
64
|
+
return nil if result.resultset.empty?
|
65
|
+
(node_id, labels, properties) = result.resultset.first["node"]
|
66
|
+
attrs = {}
|
67
|
+
|
68
|
+
properties.each do |(index, type, value)|
|
69
|
+
attrs[get_property(index)] = value
|
70
|
+
end
|
71
|
+
Node.new(label: get_label(labels.first), properties: attrs).tap do |node|
|
72
|
+
node.id = node_id
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def nodes(label: nil)
|
77
|
+
node_or_node_with_label = label ? "node:`#{label}`" : "node"
|
78
|
+
|
79
|
+
cmd = "MATCH (#{node_or_node_with_label}) RETURN node"
|
80
|
+
result = query(cmd)
|
81
|
+
|
82
|
+
result.resultset.map do |item|
|
83
|
+
(node_id, labels, properties) = item["node"]
|
84
|
+
attrs = {}
|
85
|
+
|
86
|
+
properties.each do |(index, type, value)|
|
87
|
+
attrs[get_property(index)] = value
|
88
|
+
end
|
89
|
+
Node.new(label: get_label(labels.first), properties: attrs).tap do |node|
|
90
|
+
node.id = node_id
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Adds an edge. If successul it returns the created object, otherwise false
|
96
|
+
#
|
97
|
+
def add_edge(edge)
|
98
|
+
result = query("MATCH (src), (dest)
|
99
|
+
WHERE ID(src) = #{edge.src.id} AND ID(dest) = #{edge.dest.id}
|
100
|
+
CREATE (src)-[e:`#{edge.type}` #{quote_hash(edge.properties)}]->(dest) RETURN ID(e)")
|
101
|
+
return false if result.stats[:relationships_created] != 1
|
102
|
+
id = result.resultset.first["ID(e)"]
|
103
|
+
edge.id = id
|
104
|
+
edge
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def query(cmd)
|
110
|
+
data = @connection.call("GRAPH.QUERY", graph_name, cmd, "--compact")
|
111
|
+
QueryResponse.new(data)
|
112
|
+
end
|
113
|
+
|
114
|
+
def quote_hash(hash)
|
115
|
+
out = "{"
|
116
|
+
hash.each do |k,v|
|
117
|
+
out += "#{k}:#{escape_value(v)}"
|
118
|
+
end
|
119
|
+
out + "}"
|
120
|
+
end
|
121
|
+
|
122
|
+
def escape_value(x)
|
123
|
+
case x
|
124
|
+
when Integer then x
|
125
|
+
else
|
126
|
+
"'#{x}'"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def get_label(id)
|
131
|
+
@labels ||= labels
|
132
|
+
@labels[id] || (@labels = labels)[id]
|
133
|
+
end
|
134
|
+
|
135
|
+
def get_property(id)
|
136
|
+
@properties ||= properties
|
137
|
+
@properties[id] || (@properties = properties)[id]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Redgraph
|
4
|
+
class Node
|
5
|
+
attr_accessor :id, :label, :properties
|
6
|
+
|
7
|
+
def initialize(label:, properties: {})
|
8
|
+
@label = label
|
9
|
+
@properties = properties
|
10
|
+
end
|
11
|
+
|
12
|
+
def persisted?
|
13
|
+
!id.nil?
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
super || other.instance_of?(self.class) && !id.nil? && other.id == id
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Redgraph
|
4
|
+
# Wraps the GRAPH.QUERY response, assuming we use the `--compact` output.
|
5
|
+
#
|
6
|
+
# The response is an array with these objects:
|
7
|
+
#
|
8
|
+
# - header row
|
9
|
+
# - result rows
|
10
|
+
# - query stats
|
11
|
+
#
|
12
|
+
class QueryResponse
|
13
|
+
def initialize(response)
|
14
|
+
@response = response
|
15
|
+
end
|
16
|
+
|
17
|
+
def stats
|
18
|
+
@stats ||= parse_stats
|
19
|
+
end
|
20
|
+
|
21
|
+
def entities
|
22
|
+
@entities ||= parse_header
|
23
|
+
end
|
24
|
+
|
25
|
+
def resultset
|
26
|
+
@resultset ||= parse_resultset
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# The header lists the entities described in the RETURN clause. It is an
|
32
|
+
# array of [ColumnType (enum), name (string)] elements. We can ignore the
|
33
|
+
# enum, it is always 1 (COLUMN_SCALAR).
|
34
|
+
def parse_header
|
35
|
+
@response[0].map{|item| item[1]}
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse_stats
|
39
|
+
stats = {}
|
40
|
+
|
41
|
+
@response[2].each do |item|
|
42
|
+
label, value = item.split(":")
|
43
|
+
|
44
|
+
case label
|
45
|
+
when /^Nodes created/
|
46
|
+
stats[:nodes_created] = value.to_i
|
47
|
+
when /^Relationships created/
|
48
|
+
stats[:relationships_created] = value.to_i
|
49
|
+
when /^Properties set/
|
50
|
+
stats[:properties_set] = value.to_i
|
51
|
+
when /^Query internal execution time/
|
52
|
+
stats[:internal_execution_time] = value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
stats
|
57
|
+
end
|
58
|
+
|
59
|
+
# The resultset has one element per entity (as described by the header)
|
60
|
+
def parse_resultset
|
61
|
+
@response[1].map do |item|
|
62
|
+
out = {}
|
63
|
+
|
64
|
+
item.each.with_index do |(type, value), i|
|
65
|
+
out[entities[i]] = value
|
66
|
+
end
|
67
|
+
|
68
|
+
out
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/redgraph.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/redgraph/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "redgraph"
|
7
|
+
spec.version = Redgraph::VERSION
|
8
|
+
spec.authors = ["Paolo Zaccagnini"]
|
9
|
+
spec.email = ["hi@pzac.net"]
|
10
|
+
|
11
|
+
spec.summary = "A simple RedisGraph client"
|
12
|
+
spec.homepage = "https://github.com/pzac/redgraph"
|
13
|
+
spec.license = "MIT"
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
|
15
|
+
|
16
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
17
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
18
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
|
19
|
+
|
20
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
21
|
+
`git ls-files -z`.split("\x0")
|
22
|
+
end
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
spec.add_dependency "redis", "~> 4"
|
26
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
|
5
|
+
class GraphManipulationTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@graph = Redgraph::Graph.new("movies", url: $REDIS_URL)
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
@graph.delete
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_add_node
|
15
|
+
node = Redgraph::Node.new(label: 'actor', properties: {name: "Al Pacino"})
|
16
|
+
result = @graph.add_node(node)
|
17
|
+
assert_predicate result, :persisted?
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_add_edge
|
21
|
+
actor = Redgraph::Node.new(label: 'actor', properties: {name: "Al Pacino"})
|
22
|
+
@graph.add_node(actor)
|
23
|
+
|
24
|
+
film = Redgraph::Node.new(label: 'film', properties: {name: "Scarface"})
|
25
|
+
@graph.add_node(film)
|
26
|
+
|
27
|
+
edge = Redgraph::Edge.new(src: actor, dest: film, type: 'ACTOR_IN', properties: {role: "Tony Montana"})
|
28
|
+
result = @graph.add_edge(edge)
|
29
|
+
|
30
|
+
assert_predicate result, :persisted?
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
|
5
|
+
class GraphQueriesTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@graph = Redgraph::Graph.new("movies", url: $REDIS_URL)
|
8
|
+
@actor = Redgraph::Node.new(label: 'actor', properties: {name: "Al Pacino"})
|
9
|
+
@graph.add_node(@actor)
|
10
|
+
|
11
|
+
@other_actor = Redgraph::Node.new(label: 'actor', properties: {name: "John Travolta"})
|
12
|
+
refute_nil(@actor.id)
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
@graph.delete
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_find_node_by_id
|
20
|
+
node = @graph.find_node_by_id(@actor.id)
|
21
|
+
|
22
|
+
refute_nil(node)
|
23
|
+
assert_equal("actor", node.label)
|
24
|
+
assert_equal("Al Pacino", node.properties["name"])
|
25
|
+
assert_equal(@actor.id, node.id)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_get_all_nodes
|
29
|
+
@graph.add_node(@other_actor)
|
30
|
+
|
31
|
+
actors = @graph.nodes
|
32
|
+
|
33
|
+
assert_equal(2, actors.size)
|
34
|
+
assert_includes(actors, @actor)
|
35
|
+
assert_includes(actors, @other_actor)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_get_all_nodes_by_label
|
39
|
+
@graph.add_node(@other_actor)
|
40
|
+
film = Redgraph::Node.new(label: 'film', properties: {name: "Scarface"})
|
41
|
+
@graph.add_node(film)
|
42
|
+
|
43
|
+
actors = @graph.nodes(label: 'actor')
|
44
|
+
assert_equal(2, actors.size)
|
45
|
+
assert_includes(actors, @actor)
|
46
|
+
assert_includes(actors, @other_actor)
|
47
|
+
|
48
|
+
films = @graph.nodes(label: 'film')
|
49
|
+
assert_equal(1, films.size)
|
50
|
+
assert_includes(films, film)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_find_node_by_wrong_id
|
54
|
+
node = @graph.find_node_by_id("-1")
|
55
|
+
|
56
|
+
assert_nil(node)
|
57
|
+
end
|
58
|
+
end
|
data/test/graph_test.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "test_helper"
|
4
|
+
|
5
|
+
class GraphTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@graph = create_sample_graph("foobar")
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
@graph.delete
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_list
|
15
|
+
list = @graph.list
|
16
|
+
assert_includes(list, "foobar")
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_delete
|
20
|
+
assert_includes(@graph.list, "foobar")
|
21
|
+
|
22
|
+
@graph.delete
|
23
|
+
refute_includes(@graph.list, "foobar")
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_labels
|
27
|
+
@graph = create_sample_graph("foobar")
|
28
|
+
assert_equal(["actor"], @graph.labels)
|
29
|
+
|
30
|
+
node = Redgraph::Node.new(label: "film")
|
31
|
+
@graph.add_node(node)
|
32
|
+
assert_equal(["actor", "film"], @graph.labels)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_properties
|
36
|
+
@graph = create_sample_graph("foobar")
|
37
|
+
assert_equal(["name"], @graph.properties)
|
38
|
+
|
39
|
+
node = Redgraph::Node.new(label: "actor", properties: {"age": 100})
|
40
|
+
@graph.add_node(node)
|
41
|
+
|
42
|
+
assert_equal(["name", "age"], @graph.properties)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def create_sample_graph(name)
|
48
|
+
graph = Redgraph::Graph.new(name, url: $REDIS_URL)
|
49
|
+
graph.connection.call(
|
50
|
+
"GRAPH.QUERY",
|
51
|
+
name,
|
52
|
+
"CREATE (:actor {name: 'hello'})"
|
53
|
+
)
|
54
|
+
graph
|
55
|
+
end
|
56
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
4
|
+
require "redgraph"
|
5
|
+
|
6
|
+
require "minitest/autorun"
|
7
|
+
require "pry"
|
8
|
+
|
9
|
+
unless $REDIS_URL = ENV['TEST_REDIS_URL']
|
10
|
+
puts "To run the tests you need to define the TEST_REDIS_URL environment variable"
|
11
|
+
exit(1)
|
12
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redgraph
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paolo Zaccagnini
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-04-10 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
|
+
description:
|
28
|
+
email:
|
29
|
+
- hi@pzac.net
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- ".github/workflows/main.yml"
|
35
|
+
- ".gitignore"
|
36
|
+
- CHANGELOG.md
|
37
|
+
- Gemfile
|
38
|
+
- Gemfile.lock
|
39
|
+
- LICENSE.txt
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- bin/console
|
43
|
+
- bin/setup
|
44
|
+
- lib/redgraph.rb
|
45
|
+
- lib/redgraph/edge.rb
|
46
|
+
- lib/redgraph/graph.rb
|
47
|
+
- lib/redgraph/node.rb
|
48
|
+
- lib/redgraph/query_response.rb
|
49
|
+
- lib/redgraph/version.rb
|
50
|
+
- redgraph.gemspec
|
51
|
+
- test/graph_connection_test.rb
|
52
|
+
- test/graph_manipulation_test.rb
|
53
|
+
- test/graph_queries_test.rb
|
54
|
+
- test/graph_test.rb
|
55
|
+
- test/redgraph_test.rb
|
56
|
+
- test/test_helper.rb
|
57
|
+
homepage: https://github.com/pzac/redgraph
|
58
|
+
licenses:
|
59
|
+
- MIT
|
60
|
+
metadata:
|
61
|
+
homepage_uri: https://github.com/pzac/redgraph
|
62
|
+
source_code_uri: https://github.com/pzac/redgraph
|
63
|
+
changelog_uri: https://github.com/pzac/redgraph/CHANGELOG.md
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 2.4.0
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubygems_version: 3.2.3
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: A simple RedisGraph client
|
83
|
+
test_files: []
|