redgraph 0.1.1 → 0.2.1
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 +4 -4
- data/.github/workflows/main.yml +8 -0
- data/CHANGELOG.md +26 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +22 -1
- data/README.md +109 -15
- data/lib/redgraph.rb +16 -0
- data/lib/redgraph/edge.rb +17 -4
- data/lib/redgraph/graph.rb +44 -86
- data/lib/redgraph/graph/edge_methods.rb +105 -0
- data/lib/redgraph/graph/node_methods.rb +123 -0
- data/lib/redgraph/node.rb +11 -3
- data/lib/redgraph/node_model.rb +99 -0
- data/lib/redgraph/node_model/class_methods.rb +83 -0
- data/lib/redgraph/node_model/graph_manipulation.rb +24 -0
- data/lib/redgraph/node_model/persistence.rb +56 -0
- data/lib/redgraph/query_response.rb +91 -5
- data/lib/redgraph/util.rb +21 -0
- data/lib/redgraph/version.rb +1 -1
- data/redgraph.gemspec +2 -1
- data/test/graph_edge_methods_test.rb +100 -0
- data/test/graph_manipulation_test.rb +59 -0
- data/test/graph_node_methods_test.rb +112 -0
- data/test/graph_queries_test.rb +21 -66
- data/test/graph_test.rb +26 -0
- data/test/node_model_class_methods_test.rb +93 -0
- data/test/node_model_labels_test.rb +57 -0
- data/test/node_model_persistence_test.rb +70 -0
- data/test/node_model_test.rb +136 -0
- data/test/test_helper.rb +21 -0
- metadata +30 -3
@@ -0,0 +1,56 @@
|
|
1
|
+
module Redgraph
|
2
|
+
module NodeModel
|
3
|
+
module Persistence
|
4
|
+
# Adds the node to the graph
|
5
|
+
#
|
6
|
+
# - allow_duplicates: if false it will create a node with the same type and properties only if
|
7
|
+
# not present
|
8
|
+
#
|
9
|
+
def add_to_graph(allow_duplicates: true)
|
10
|
+
raise MissingGraphError unless graph
|
11
|
+
item = allow_duplicates ? graph.add_node(to_node) : graph.merge_node(to_node)
|
12
|
+
self.id = item.id
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
# Creates a new record or updates the existing
|
17
|
+
#
|
18
|
+
def save
|
19
|
+
if persisted?
|
20
|
+
item = graph.update_node(to_node)
|
21
|
+
self.class.reify_from_node(item)
|
22
|
+
else
|
23
|
+
add_to_graph
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def persisted?
|
28
|
+
id.present?
|
29
|
+
end
|
30
|
+
|
31
|
+
def reload
|
32
|
+
item = self.class.find(id)
|
33
|
+
@label = item.label
|
34
|
+
assign_attributes(item.attributes)
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
# Deletes the record from the graph
|
39
|
+
#
|
40
|
+
def destroy
|
41
|
+
@destroyed = true
|
42
|
+
if graph.destroy_node(self)
|
43
|
+
self
|
44
|
+
else
|
45
|
+
false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns true if this object has been destroyed, otherwise returns false.
|
50
|
+
#
|
51
|
+
def destroyed?
|
52
|
+
!!@destroyed
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -10,8 +10,35 @@ module Redgraph
|
|
10
10
|
# - query stats
|
11
11
|
#
|
12
12
|
class QueryResponse
|
13
|
-
|
13
|
+
TYPES = [
|
14
|
+
UNKNOWN = 0,
|
15
|
+
NULL = 1,
|
16
|
+
STRING = 2,
|
17
|
+
INTEGER = 3,
|
18
|
+
BOOLEAN = 4,
|
19
|
+
DOUBLE = 5,
|
20
|
+
ARRAY = 6,
|
21
|
+
EDGE = 7,
|
22
|
+
NODE = 8,
|
23
|
+
PATH = 9,
|
24
|
+
MAP = 10,
|
25
|
+
POINT = 11
|
26
|
+
].freeze
|
27
|
+
|
28
|
+
def initialize(response, graph)
|
14
29
|
@response = response
|
30
|
+
@graph = graph
|
31
|
+
|
32
|
+
case @response.size
|
33
|
+
when 3
|
34
|
+
@header_row = @response[0]
|
35
|
+
@result_rows = @response[1]
|
36
|
+
@query_statistics = @response[2]
|
37
|
+
when 1 # queries with no RETURN clause
|
38
|
+
@header_row = []
|
39
|
+
@result_rows = []
|
40
|
+
@query_statistics = @response[0]
|
41
|
+
end
|
15
42
|
end
|
16
43
|
|
17
44
|
def stats
|
@@ -26,24 +53,83 @@ module Redgraph
|
|
26
53
|
@resultset ||= parse_resultset
|
27
54
|
end
|
28
55
|
|
56
|
+
# Wraps in custom datatypes if needed
|
57
|
+
#
|
58
|
+
def rows
|
59
|
+
@result_rows.map do |column|
|
60
|
+
column.map do |data|
|
61
|
+
reify_column_item(data)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
29
67
|
private
|
30
68
|
|
69
|
+
def reify_column_item(data)
|
70
|
+
value_type, value = data
|
71
|
+
|
72
|
+
case value_type
|
73
|
+
when STRING, INTEGER, BOOLEAN, DOUBLE then value
|
74
|
+
when NODE then reify_node_item(value)
|
75
|
+
when EDGE then reify_edge_item(value)
|
76
|
+
else
|
77
|
+
"other"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def reify_node_item(data)
|
82
|
+
(node_id, labels, props) = data
|
83
|
+
|
84
|
+
label = @graph.get_label(labels[0]) # Only one label is currently supported
|
85
|
+
|
86
|
+
node = Node.new(label: label)
|
87
|
+
node.id = node_id
|
88
|
+
|
89
|
+
props.each do |(prop_id, prop_type, prop_value)|
|
90
|
+
prop_name = @graph.get_property(prop_id)
|
91
|
+
node.properties[prop_name] = prop_value
|
92
|
+
end
|
93
|
+
|
94
|
+
node
|
95
|
+
end
|
96
|
+
|
97
|
+
def reify_edge_item(data)
|
98
|
+
(edge_id, type_id, src_id, dest_id, props) = data
|
99
|
+
|
100
|
+
type = @graph.get_relationship_type(type_id)
|
101
|
+
|
102
|
+
edge = Edge.new(type: type)
|
103
|
+
edge.id = edge_id
|
104
|
+
edge.src_id = src_id
|
105
|
+
edge.dest_id = dest_id
|
106
|
+
|
107
|
+
props.each do |(prop_id, prop_type, prop_value)|
|
108
|
+
prop_name = @graph.get_property(prop_id)
|
109
|
+
edge.properties[prop_name] = prop_value
|
110
|
+
end
|
111
|
+
|
112
|
+
edge
|
113
|
+
end
|
114
|
+
|
31
115
|
# The header lists the entities described in the RETURN clause. It is an
|
32
116
|
# array of [ColumnType (enum), name (string)] elements. We can ignore the
|
33
117
|
# enum, it is always 1 (COLUMN_SCALAR).
|
34
118
|
def parse_header
|
35
|
-
@
|
119
|
+
@header_row.map{|item| item[1]}
|
36
120
|
end
|
37
121
|
|
38
122
|
def parse_stats
|
39
123
|
stats = {}
|
40
124
|
|
41
|
-
@
|
125
|
+
@query_statistics.each do |item|
|
42
126
|
label, value = item.split(":")
|
43
127
|
|
44
128
|
case label
|
45
129
|
when /^Nodes created/
|
46
130
|
stats[:nodes_created] = value.to_i
|
131
|
+
when /^Nodes deleted/
|
132
|
+
stats[:nodes_deleted] = value.to_i
|
47
133
|
when /^Relationships created/
|
48
134
|
stats[:relationships_created] = value.to_i
|
49
135
|
when /^Properties set/
|
@@ -58,8 +144,8 @@ module Redgraph
|
|
58
144
|
|
59
145
|
# The resultset has one element per entity (as described by the header)
|
60
146
|
def parse_resultset
|
61
|
-
@
|
62
|
-
out =
|
147
|
+
@result_rows.map do |item|
|
148
|
+
out = HashWithIndifferentAccess.new
|
63
149
|
|
64
150
|
item.each.with_index do |(type, value), i|
|
65
151
|
out[entities[i]] = value
|
@@ -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
|
data/lib/redgraph/version.rb
CHANGED
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
|