redgraph 0.1.0 → 0.2.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.
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Redgraph
4
+ module Util
5
+ def properties_to_string(hash)
6
+ return if hash.empty?
7
+ "{" +
8
+ hash.map {|k,v| "#{k}:#{escape_value(v)}" }.join(", ") +
9
+ "}"
10
+ end
11
+
12
+ def escape_value(x)
13
+ case x
14
+ when Integer then x
15
+ when NilClass then "''"
16
+ else
17
+ '"' + x.gsub('"', '\"') + '"'
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Redgraph
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/redgraph.gemspec CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
15
15
 
16
16
  spec.metadata["homepage_uri"] = spec.homepage
17
17
  spec.metadata["source_code_uri"] = spec.homepage
18
- spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
18
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md"
19
19
 
20
20
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
21
21
  `git ls-files -z`.split("\x0")
@@ -23,4 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ["lib"]
24
24
 
25
25
  spec.add_dependency "redis", "~> 4"
26
+ spec.add_dependency "activesupport", ">= 3.0.0"
26
27
  end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class GraphEdgeMethodsTest < Minitest::Test
6
+ include TestHelpers
7
+
8
+ def setup
9
+ @graph = Redgraph::Graph.new("movies", url: $REDIS_URL)
10
+
11
+ @al = quick_add_node(label: 'actor', properties: {name: "Al Pacino"})
12
+ @john = quick_add_node(label: 'actor', properties: {name: "John Travolta"})
13
+ end
14
+
15
+ def teardown
16
+ @graph.delete
17
+ end
18
+
19
+ def test_find_edge
20
+ quick_add_edge(type: 'FRIEND_OF', src: @al, dest: @john, properties: {since: 1980})
21
+ edge = @graph.edges.first
22
+
23
+ assert_equal('FRIEND_OF', edge.type)
24
+ assert_equal(1980, edge.properties["since"])
25
+ assert_equal(@al, edge.src)
26
+ assert_equal(@john, edge.dest)
27
+ end
28
+
29
+ def test_find_all_edges
30
+ marlon = quick_add_node(label: 'actor', properties: {name: "Marlon Brando"})
31
+ film = quick_add_node(label: 'film', properties: {name: "The Godfather"})
32
+ quick_add_edge(type: 'ACTOR_IN', src: marlon, dest: film, properties: {role: 'Don Vito'})
33
+ quick_add_edge(type: 'ACTOR_IN', src: @al, dest: film, properties: {role: 'Michael'})
34
+
35
+ edges = @graph.edges
36
+ assert_equal(2, edges.size)
37
+ end
38
+
39
+ def test_count_edges
40
+ marlon = quick_add_node(label: 'actor', properties: {name: "Marlon Brando"})
41
+ film = quick_add_node(label: 'film', properties: {name: "The Godfather"})
42
+ quick_add_edge(type: 'ACTOR_IN', src: marlon, dest: film, properties: {role: 'Don Vito'})
43
+ quick_add_edge(type: 'ACTOR_IN', src: @al, dest: film, properties: {role: 'Michael'})
44
+
45
+ assert_equal(2, @graph.count_edges)
46
+ end
47
+
48
+ def test_filter_edges
49
+ marlon = quick_add_node(label: 'actor', properties: {name: "Marlon Brando"})
50
+ film = quick_add_node(label: 'film', properties: {name: "The Godfather"})
51
+ other_film = quick_add_node(label: 'film', properties: {name: "Carlito's Way"})
52
+ e_donvito = quick_add_edge(type: 'ACTOR_IN', src: marlon, dest: film, properties: {role: 'Don Vito'})
53
+ e_michael = quick_add_edge(type: 'ACTOR_IN', src: @al, dest: film, properties: {role: 'Michael'})
54
+ e_carlito = quick_add_edge(type: 'ACTOR_IN', src: @al, dest: other_film, properties: {role: 'Carlito'})
55
+ quick_add_edge(type: 'FRIEND_OF', src: @al, dest: marlon, properties: {since: 1980})
56
+
57
+ edges = @graph.edges(type: "FRIEND_OF")
58
+ assert_equal(1, edges.size)
59
+
60
+ edges = @graph.edges(type: "ACTOR_IN")
61
+ assert_equal(3, edges.size)
62
+
63
+ edges = @graph.edges(type: "ACTOR_IN", limit: 2)
64
+ assert_equal(2, edges.size)
65
+
66
+ edges = @graph.edges(type: "ACTOR_IN", skip: 2, limit: 10)
67
+ assert_equal(1, edges.size)
68
+
69
+ edges = @graph.edges(properties: {role: "Carlito"})
70
+ assert_equal([e_carlito], edges)
71
+
72
+ edges = @graph.edges(src: marlon)
73
+ assert_equal([e_donvito], edges)
74
+
75
+ edges = @graph.edges(type: 'ACTOR_IN', dest: film)
76
+ assert_equal(2, edges.size)
77
+ assert_includes(edges, e_donvito)
78
+ assert_includes(edges, e_michael)
79
+
80
+ edges = @graph.edges(src: @al, dest: marlon)
81
+ assert_equal(1, edges.size)
82
+ edge = edges[0]
83
+ assert_equal('FRIEND_OF', edge.type)
84
+ assert_equal(1980, edge.properties["since"])
85
+ end
86
+
87
+ def test_order_edges
88
+ marlon = quick_add_node(label: 'actor', properties: {name: "Marlon Brando"})
89
+
90
+ e1 = quick_add_edge(type: 'FRIEND_OF', src: @al, dest: marlon, properties: {since: 1980})
91
+ e2 = quick_add_edge(type: 'FRIEND_OF', src: @al, dest: @john, properties: {since: 2000})
92
+ e3 = quick_add_edge(type: 'FRIEND_OF', src: marlon, dest: @john, properties: {since: 1990})
93
+
94
+ edges = @graph.edges(type: 'FRIEND_OF', order: "edge.since ASC")
95
+ assert_equal([e1, e3, e2], edges)
96
+
97
+ edges = @graph.edges(type: 'FRIEND_OF', order: "edge.since DESC")
98
+ assert_equal([e2, e3, e1], edges)
99
+ end
100
+ end
@@ -3,6 +3,8 @@
3
3
  require "test_helper"
4
4
 
5
5
  class GraphManipulationTest < Minitest::Test
6
+ include TestHelpers
7
+
6
8
  def setup
7
9
  @graph = Redgraph::Graph.new("movies", url: $REDIS_URL)
8
10
  end
@@ -17,6 +19,35 @@ class GraphManipulationTest < Minitest::Test
17
19
  assert_predicate result, :persisted?
18
20
  end
19
21
 
22
+ def test_add_node_with_special_chars
23
+ [
24
+ "apo'str",
25
+ "two''apos",
26
+ "Foø'bÆ®",
27
+ "aa\nbb",
28
+ 'aaa "bbb" ccc'
29
+ ].each do |name|
30
+
31
+ node = Redgraph::Node.new(label: 'actor', properties: {name: name})
32
+ result = @graph.add_node(node)
33
+ assert_predicate result, :persisted?
34
+
35
+ item = @graph.find_node_by_id(node.id)
36
+
37
+ assert_equal(name, item.properties["name"])
38
+ end
39
+ end
40
+
41
+ def test_add_node_with_nil_value
42
+ node = Redgraph::Node.new(label: 'actor', properties: {name: nil})
43
+ result = @graph.add_node(node)
44
+ assert_predicate result, :persisted?
45
+
46
+ item = @graph.find_node_by_id(node.id)
47
+
48
+ assert_equal("", item.properties["name"])
49
+ end
50
+
20
51
  def test_add_edge
21
52
  actor = Redgraph::Node.new(label: 'actor', properties: {name: "Al Pacino"})
22
53
  @graph.add_node(actor)
@@ -29,4 +60,32 @@ class GraphManipulationTest < Minitest::Test
29
60
 
30
61
  assert_predicate result, :persisted?
31
62
  end
63
+
64
+ def test_merge_node
65
+ quick_add_node(label: 'actor', properties: {name: "Al Pacino"})
66
+ quick_add_node(label: 'actor', properties: {name: "John Travolta"})
67
+
68
+ nodes = @graph.nodes(label: 'actor')
69
+ assert_equal(2, nodes.size)
70
+
71
+ @graph.merge_node(Redgraph::Node.new(label: 'actor', properties: {name: "Joe Pesci"}))
72
+ assert_equal(3, @graph.nodes(label: 'actor').size)
73
+
74
+ @graph.merge_node(Redgraph::Node.new(label: 'actor', properties: {name: "Al Pacino"}))
75
+ assert_equal(3, @graph.nodes(label: 'actor').size)
76
+ end
77
+
78
+ def test_merge_edge
79
+ al = quick_add_node(label: 'actor', properties: {name: "Al Pacino"})
80
+ john = quick_add_node(label: 'actor', properties: {name: "John Travolta"})
81
+
82
+ assert_equal(0, @graph.edges.size)
83
+
84
+ edge = Redgraph::Edge.new(type: 'FRIEND_OF', src: al, dest: john, properties: {since: 1990})
85
+ @graph.merge_edge(edge)
86
+ assert_equal(1, @graph.edges.size)
87
+
88
+ @graph.merge_edge(edge)
89
+ assert_equal(1, @graph.edges.size)
90
+ end
32
91
  end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ class GraphNodeMethodsTest < Minitest::Test
6
+ include TestHelpers
7
+
8
+ def setup
9
+ @graph = Redgraph::Graph.new("movies", url: $REDIS_URL)
10
+
11
+ @al = quick_add_node(label: 'actor', properties: {name: "Al Pacino"})
12
+ @john = quick_add_node(label: 'actor', properties: {name: "John Travolta"})
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(@al.id)
21
+
22
+ refute_nil(node)
23
+ assert_equal("actor", node.label)
24
+ assert_equal("Al Pacino", node.properties["name"])
25
+ assert_equal(@al.id, node.id)
26
+ end
27
+
28
+ def test_find_node_by_wrong_id
29
+ node = @graph.find_node_by_id("-1")
30
+
31
+ assert_nil(node)
32
+ end
33
+
34
+ def test_find_all_nodes
35
+ actors = @graph.nodes
36
+
37
+ assert_equal(2, actors.size)
38
+ assert_includes(actors, @al)
39
+ assert_includes(actors, @john)
40
+ end
41
+
42
+ def test_find_all_nodes_by_label
43
+ film = quick_add_node(label: 'film', properties: {name: "Scarface"})
44
+
45
+ actors = @graph.nodes(label: 'actor')
46
+ assert_equal(2, actors.size)
47
+ assert_includes(actors, @al)
48
+ assert_includes(actors, @john)
49
+
50
+ films = @graph.nodes(label: 'film')
51
+ assert_equal(1, films.size)
52
+ assert_includes(films, film)
53
+ end
54
+
55
+ def test_find_all_nodes_by_property
56
+ scarface = quick_add_node(label: 'film', properties: {name: "Scarface", genre: "drama"})
57
+ casino = quick_add_node(label: 'film', properties: {name: "Casino", genre: "drama"})
58
+ _mamma_mia = quick_add_node(label: 'film', properties: {name: "Mamma Mia", genre: "musical"})
59
+
60
+ dramas = @graph.nodes(properties: {genre: "drama"})
61
+
62
+ assert_equal(2, dramas.size)
63
+ assert_includes(dramas, scarface)
64
+ assert_includes(dramas, casino)
65
+ end
66
+
67
+ def test_order_nodes_by_property
68
+ scarface = quick_add_node(label: 'film', properties: {name: "Scarface", genre: "drama"})
69
+ casino = quick_add_node(label: 'film', properties: {name: "Casino", genre: "drama"})
70
+ mamma_mia = quick_add_node(label: 'film', properties: {name: "Mamma Mia", genre: "musical"})
71
+
72
+ items = @graph.nodes(label: 'film', order: "node.name")
73
+ assert_equal([casino, mamma_mia, scarface], items)
74
+
75
+ items = @graph.nodes(label: 'film', order: "node.name ASC")
76
+ assert_equal([casino, mamma_mia, scarface], items)
77
+
78
+ items = @graph.nodes(label: 'film', order: "node.name DESC")
79
+ assert_equal([scarface, mamma_mia, casino], items)
80
+ end
81
+
82
+ def test_count_nodes
83
+ quick_add_node(label: 'film', properties: {name: "Scarface", genre: "drama"})
84
+ quick_add_node(label: 'film', properties: {name: "Casino", genre: "drama"})
85
+ quick_add_node(label: 'film', properties: {name: "Mamma Mia", genre: "musical"})
86
+
87
+
88
+ assert_equal(5, @graph.count_nodes)
89
+ assert_equal(3, @graph.count_nodes(label: 'film'))
90
+ assert_equal(2, @graph.count_nodes(properties: {genre: "drama"}))
91
+ end
92
+
93
+ def test_limit_nodes
94
+ 10.times do |i|
95
+ quick_add_node(label: 'token', properties: {number: i})
96
+ end
97
+
98
+ items = @graph.nodes(label: 'token', limit: 5)
99
+ assert_equal(5, items.size)
100
+ assert_equal([0,1,2,3,4], items.map{|item| item.properties["number"]})
101
+ end
102
+
103
+ def test_skip_nodes
104
+ 10.times do |i|
105
+ quick_add_node(label: 'token', properties: {number: i})
106
+ end
107
+
108
+ items = @graph.nodes(label: 'token', limit: 3, skip: 3)
109
+ assert_equal(3, items.size)
110
+ assert_equal([3,4,5], items.map{|item| item.properties["number"]})
111
+ end
112
+ end
@@ -3,56 +3,43 @@
3
3
  require "test_helper"
4
4
 
5
5
  class GraphQueriesTest < Minitest::Test
6
+ include TestHelpers
7
+
6
8
  def setup
7
9
  @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
10
 
11
- @other_actor = Redgraph::Node.new(label: 'actor', properties: {name: "John Travolta"})
12
- refute_nil(@actor.id)
11
+ @al = quick_add_node(label: 'actor', properties: {name: "Al Pacino", born: 1940})
12
+ @john = quick_add_node(label: 'actor', properties: {name: "John Travolta", born: 1954})
13
13
  end
14
14
 
15
15
  def teardown
16
16
  @graph.delete
17
17
  end
18
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)
19
+ def test_query_string_attribute
20
+ result = @graph.query("MATCH (n) RETURN n.name ORDER BY n.name")
21
+ assert_equal([["Al Pacino"], ["John Travolta"]], result)
26
22
  end
27
23
 
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)
24
+ def test_query_string_and_number_attributes
25
+ result = @graph.query("MATCH (n) RETURN n.name, n.born ORDER BY n.born")
26
+ assert_equal([["Al Pacino", 1940], ["John Travolta", 1954]], result)
36
27
  end
37
28
 
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)
29
+ def test_query_nodes
30
+ result = @graph.query("MATCH (n) RETURN n ORDER BY n.born")
31
+ assert_equal([[@al], [@john]], result)
51
32
  end
52
33
 
53
- def test_find_node_by_wrong_id
54
- node = @graph.find_node_by_id("-1")
34
+ def test_query_edge
35
+ edge = quick_add_edge(type: 'FRIEND_OF', src: @al, dest: @john, properties: {since: 1980})
36
+ result = @graph.query("MATCH (src)-[edge]->(dest) RETURN edge")
37
+ assert_equal([[edge]], result)
38
+ end
55
39
 
56
- assert_nil(node)
40
+ def test_query_node_and_edge
41
+ edge = quick_add_edge(type: 'FRIEND_OF', src: @al, dest: @john, properties: {since: 1980})
42
+ result = @graph.query("MATCH (src)-[edge:FRIEND_OF]->(dest) RETURN src, edge")
43
+ assert_equal([[@al, edge]], result)
57
44
  end
58
45
  end
data/test/graph_test.rb CHANGED
@@ -12,11 +12,13 @@ class GraphTest < Minitest::Test
12
12
  end
13
13
 
14
14
  def test_list
15
+ skip unless graph_list_supported?
15
16
  list = @graph.list
16
17
  assert_includes(list, "foobar")
17
18
  end
18
19
 
19
20
  def test_delete
21
+ skip unless graph_list_supported?
20
22
  assert_includes(@graph.list, "foobar")
21
23
 
22
24
  @graph.delete
@@ -42,6 +44,19 @@ class GraphTest < Minitest::Test
42
44
  assert_equal(["name", "age"], @graph.properties)
43
45
  end
44
46
 
47
+ def test_relationship_types
48
+ @graph = create_sample_graph("foobar")
49
+
50
+ actor = Redgraph::Node.new(label: "actor", properties: {"name": "Harrison Ford"})
51
+ @graph.add_node(actor)
52
+ film = Redgraph::Node.new(label: "film", properties: {"name": "Star Wars"})
53
+ @graph.add_node(film)
54
+ edge = Redgraph::Edge.new(type: "ACTED_IN", src: actor, dest: film)
55
+ @graph.add_edge(edge)
56
+
57
+ assert_equal(["ACTED_IN"], @graph.relationship_types)
58
+ end
59
+
45
60
  private
46
61
 
47
62
  def create_sample_graph(name)
@@ -53,4 +68,15 @@ class GraphTest < Minitest::Test
53
68
  )
54
69
  graph
55
70
  end
71
+
72
+ # This command is only supported in the latest version
73
+ def graph_list_supported?
74
+ @graph.list
75
+ rescue Redis::CommandError => e
76
+ if e.message =~ /ERR unknown command `GRAPH.LIST`/
77
+ false
78
+ else
79
+ true
80
+ end
81
+ end
56
82
  end