neography 1.0.10 → 1.0.11
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.
- data/.travis.yml +1 -1
- data/README.md +1 -0
- data/lib/neography/connection.rb +45 -34
- data/lib/neography/node.rb +1 -1
- data/lib/neography/path_traverser.rb +9 -4
- data/lib/neography/property_container.rb +16 -4
- data/lib/neography/rest.rb +86 -2
- data/lib/neography/rest/batch.rb +4 -12
- data/lib/neography/rest/cypher.rb +12 -3
- data/lib/neography/rest/helpers.rb +12 -0
- data/lib/neography/rest/node_labels.rb +60 -0
- data/lib/neography/rest/node_relationships.rb +0 -11
- data/lib/neography/rest/other_node_relationships.rb +1 -12
- data/lib/neography/rest/relationship_types.rb +18 -0
- data/lib/neography/rest/schema_indexes.rb +34 -0
- data/lib/neography/rest/transactions.rb +83 -0
- data/lib/neography/tasks.rb +1 -1
- data/lib/neography/version.rb +1 -1
- data/spec/integration/node_spec.rb +13 -0
- data/spec/integration/rest_batch_spec.rb +11 -15
- data/spec/integration/rest_batch_streaming_spec.rb +2 -2
- data/spec/integration/rest_gremlin_fail_spec.rb +4 -4
- data/spec/integration/rest_header_spec.rb +1 -1
- data/spec/integration/rest_labels_spec.rb +131 -0
- data/spec/integration/rest_plugin_spec.rb +32 -3
- data/spec/integration/rest_relationship_types_spec.rb +18 -0
- data/spec/integration/rest_schema_index_spec.rb +32 -0
- data/spec/integration/rest_transaction_spec.rb +100 -0
- data/spec/spec_helper.rb +8 -1
- data/spec/unit/connection_spec.rb +1 -1
- data/spec/unit/node_spec.rb +1 -1
- data/spec/unit/rest/batch_spec.rb +21 -21
- data/spec/unit/rest/labels_spec.rb +73 -0
- data/spec/unit/rest/relationship_types_spec.rb +16 -0
- data/spec/unit/rest/schema_index_spec.rb +31 -0
- data/spec/unit/rest/transactions_spec.rb +44 -0
- metadata +22 -2
@@ -37,17 +37,6 @@ module Neography
|
|
37
37
|
node_relationships
|
38
38
|
end
|
39
39
|
|
40
|
-
def parse_direction(direction)
|
41
|
-
case direction
|
42
|
-
when :incoming, "incoming", :in, "in"
|
43
|
-
"in"
|
44
|
-
when :outgoing, "outgoing", :out, "out"
|
45
|
-
"out"
|
46
|
-
else
|
47
|
-
"all"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
40
|
end
|
52
41
|
end
|
53
42
|
end
|
@@ -36,24 +36,13 @@ module Neography
|
|
36
36
|
}.merge(relationships).to_json,
|
37
37
|
:headers => json_content_type
|
38
38
|
}
|
39
|
-
|
39
|
+
|
40
40
|
node_relationships = @connection.post(base_path(:id => get_id(id)), options) || []
|
41
41
|
|
42
42
|
return nil if node_relationships.empty?
|
43
43
|
node_relationships
|
44
44
|
end
|
45
45
|
|
46
|
-
def parse_direction(direction)
|
47
|
-
case direction
|
48
|
-
when :incoming, "incoming", :in, "in"
|
49
|
-
"in"
|
50
|
-
when :outgoing, "outgoing", :out, "out"
|
51
|
-
"out"
|
52
|
-
else
|
53
|
-
"all"
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
46
|
end
|
58
47
|
end
|
59
48
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Neography
|
2
|
+
class Rest
|
3
|
+
class RelationshipTypes
|
4
|
+
extend Neography::Rest::Paths
|
5
|
+
|
6
|
+
add_path :all, "/relationship/types"
|
7
|
+
|
8
|
+
def initialize(connection)
|
9
|
+
@connection = connection
|
10
|
+
end
|
11
|
+
|
12
|
+
def list
|
13
|
+
@connection.get(all_path)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Neography
|
2
|
+
class Rest
|
3
|
+
class SchemaIndexes
|
4
|
+
extend Neography::Rest::Paths
|
5
|
+
include Neography::Rest::Helpers
|
6
|
+
|
7
|
+
add_path :base, "/schema/index/:label"
|
8
|
+
add_path :drop, "/schema/index/:label/:index"
|
9
|
+
|
10
|
+
def initialize(connection)
|
11
|
+
@connection = connection
|
12
|
+
end
|
13
|
+
|
14
|
+
def list(label)
|
15
|
+
@connection.get(base_path(:label => label))
|
16
|
+
end
|
17
|
+
|
18
|
+
def drop(label, index)
|
19
|
+
@connection.delete(drop_path(:label => label, :index => index))
|
20
|
+
end
|
21
|
+
|
22
|
+
def create(label, keys = [])
|
23
|
+
options = {
|
24
|
+
:body => (
|
25
|
+
{ :property_keys => keys
|
26
|
+
}
|
27
|
+
).to_json,
|
28
|
+
:headers => json_content_type
|
29
|
+
}
|
30
|
+
@connection.post(base_path(:label => label), options)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Neography
|
2
|
+
class Rest
|
3
|
+
class Transactions
|
4
|
+
extend Neography::Rest::Paths
|
5
|
+
include Neography::Rest::Helpers
|
6
|
+
|
7
|
+
add_path :base, "/transaction"
|
8
|
+
add_path :tx, "/transaction/:id"
|
9
|
+
add_path :commit, "/transaction/:id/commit"
|
10
|
+
|
11
|
+
def initialize(connection)
|
12
|
+
@connection = connection
|
13
|
+
end
|
14
|
+
|
15
|
+
def begin(statements = [], commit = "")
|
16
|
+
options = {
|
17
|
+
:body => (
|
18
|
+
convert_cypher(statements)
|
19
|
+
).to_json,
|
20
|
+
:headers => json_content_type
|
21
|
+
}
|
22
|
+
@connection.post(base_path + commit, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def add(tx, statements = [])
|
26
|
+
options = {
|
27
|
+
:body => (
|
28
|
+
convert_cypher(statements)
|
29
|
+
).to_json,
|
30
|
+
:headers => json_content_type
|
31
|
+
}
|
32
|
+
@connection.post(tx_path(:id => get_id(tx)), options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def commit(tx, statements = [])
|
36
|
+
options = {
|
37
|
+
:body => (
|
38
|
+
convert_cypher(statements)
|
39
|
+
).to_json,
|
40
|
+
:headers => json_content_type
|
41
|
+
}
|
42
|
+
@connection.post(commit_path(:id => get_id(tx)), options)
|
43
|
+
end
|
44
|
+
|
45
|
+
def rollback(tx)
|
46
|
+
@connection.delete(tx_path(:id => get_id(tx)))
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def get_id(tx)
|
52
|
+
return tx if tx.is_a?(Integer)
|
53
|
+
return tx.split("/")[-2] if tx.is_a?(String)
|
54
|
+
return tx["commit"].split("/")[-2] if tx["commit"]
|
55
|
+
raise NeographyError.new("Could not determine transaction id", nil, tx)
|
56
|
+
end
|
57
|
+
|
58
|
+
def convert_cypher(statements)
|
59
|
+
array = []
|
60
|
+
query = nil
|
61
|
+
parameters = nil
|
62
|
+
Array(statements).each do |statement|
|
63
|
+
if query & parameters
|
64
|
+
array << {:statement => query, :parameters => {:props => parameters}}
|
65
|
+
query = statement
|
66
|
+
parameters = nil
|
67
|
+
elsif query & statement.is_a?(String)
|
68
|
+
array << {:statement => query}
|
69
|
+
query = statement
|
70
|
+
parameters = nil
|
71
|
+
elsif query & statement.is_a?(Hash)
|
72
|
+
array << {:statement => query, :parameters => {:props => parameters}}
|
73
|
+
query = nil
|
74
|
+
parameters = nil
|
75
|
+
end
|
76
|
+
query = statement
|
77
|
+
end
|
78
|
+
array << {:statement => query} if query
|
79
|
+
{ :statements => array }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/neography/tasks.rb
CHANGED
@@ -6,7 +6,7 @@ require 'zip/zip'
|
|
6
6
|
namespace :neo4j do
|
7
7
|
desc "Install Neo4j"
|
8
8
|
task :install, :edition, :version do |t, args|
|
9
|
-
args.with_defaults(:edition => "community", :version => "1.
|
9
|
+
args.with_defaults(:edition => "community", :version => "1.9")
|
10
10
|
puts "Installing Neo4j-#{args[:edition]}-#{args[:version]}"
|
11
11
|
|
12
12
|
if OS::Underlying.windows?
|
data/lib/neography/version.rb
CHANGED
@@ -68,6 +68,19 @@ describe Neography::Node do
|
|
68
68
|
existing_node = Neography::Node.load(@neo, new_node)
|
69
69
|
}.to raise_error(ArgumentError)
|
70
70
|
end
|
71
|
+
|
72
|
+
it "can get a node that exists via cypher" do
|
73
|
+
new_node = Neography::Node.create("age" => 31, "name" => "Max")
|
74
|
+
cypher = "START n = node({id}) return n"
|
75
|
+
@neo = Neography::Rest.new
|
76
|
+
results = @neo.execute_query(cypher, {:id => new_node.neo_id.to_i})
|
77
|
+
existing_node = Neography::Node.load(results)
|
78
|
+
existing_node.should_not be_nil
|
79
|
+
existing_node.neo_id.should_not be_nil
|
80
|
+
existing_node.neo_id.should == new_node.neo_id
|
81
|
+
end
|
82
|
+
|
83
|
+
|
71
84
|
end
|
72
85
|
|
73
86
|
describe "del" do
|
@@ -255,14 +255,14 @@ describe Neography::Rest do
|
|
255
255
|
batch_result.first["body"].first["end"].split('/').last.should == node2["self"].split('/').last
|
256
256
|
end
|
257
257
|
|
258
|
-
it "can batch gremlin" do
|
258
|
+
it "can batch gremlin", :gremlin => true do
|
259
259
|
batch_result = @neo.batch [:execute_script, "g.v(0)"]
|
260
260
|
batch_result.first.should have_key("id")
|
261
261
|
batch_result.first.should have_key("from")
|
262
262
|
batch_result.first["body"]["self"].split('/').last.should == "0"
|
263
263
|
end
|
264
264
|
|
265
|
-
it "can batch gremlin with parameters" do
|
265
|
+
it "can batch gremlin with parameters", :gremlin => true do
|
266
266
|
new_node = @neo.create_node
|
267
267
|
id = new_node["self"].split('/').last
|
268
268
|
batch_result = @neo.batch [:execute_script, "g.v(id)", {:id => id.to_i}]
|
@@ -445,38 +445,34 @@ describe Neography::Rest do
|
|
445
445
|
# See https://github.com/neo4j/community/issues/697
|
446
446
|
|
447
447
|
expect {
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
448
|
+
batch_result = @neo.batch [:create_unique_node, "person", "ssn", "000-00-0001", {:first_name=>"Jane", :last_name=>"Doe", :ssn=>"000-00-0001", :_type=>"Person", :created_at=>1335269478}],
|
449
|
+
[:add_node_to_index, "person_ssn", "ssn", "000-00-0001", "{0}"],
|
450
|
+
[:create_node, {:street1=>"94437 Kemmer Crossing", :street2=>"Apt. 333", :city=>"Abshireton", :state=>"AA", :zip=>"65820", :_type=>"Address", :created_at=>1335269478}],
|
451
|
+
[:create_relationship, "has", "{0}", "{2}", {}]
|
452
|
+
}.to raise_error(Neography::NeographyError)
|
453
453
|
end
|
454
454
|
|
455
455
|
end
|
456
456
|
|
457
457
|
describe "broken queries" do
|
458
458
|
it "should return errors when bad syntax is passed in batch" do
|
459
|
-
|
460
459
|
batch_commands = []
|
461
|
-
# batch_commands << [ :create_unique_node, "person", "ssn", "000-00-0002", {:foo => "bar"} ]
|
462
460
|
|
463
|
-
# this doesn't raise error
|
464
461
|
batch_commands << [ :execute_query, "start person_n=node:person(ssn = '000-00-0002')
|
465
|
-
|
462
|
+
set bar1 = {foo}",
|
466
463
|
{ :other => "what" }
|
467
464
|
]
|
468
465
|
|
466
|
+
expect {
|
467
|
+
batch_result = @neo.batch *batch_commands
|
468
|
+
}.to raise_exception Neography::SyntaxException
|
469
469
|
|
470
|
-
# this does raise error
|
471
470
|
expect {
|
472
471
|
@neo.execute_query("start person_n=node:person(ssn = '000-00-0001')
|
473
472
|
set bar = {foo}",
|
474
473
|
{ :other => "what" })
|
475
474
|
}.to raise_exception Neography::SyntaxException
|
476
475
|
|
477
|
-
expect {
|
478
|
-
batch_result = @neo.batch *batch_commands
|
479
|
-
}.to raise_exception Neography::SyntaxException
|
480
476
|
|
481
477
|
end
|
482
478
|
end
|
@@ -17,9 +17,9 @@ describe Neography::Rest do
|
|
17
17
|
batch_result.last["body"]["data"]["name"].should == "Max 999"
|
18
18
|
end
|
19
19
|
|
20
|
-
it "can send a
|
20
|
+
it "can send a 5000 item batch" do
|
21
21
|
commands = []
|
22
|
-
|
22
|
+
5000.times do |x|
|
23
23
|
commands << [:get_node, 0]
|
24
24
|
end
|
25
25
|
batch_result = @neo.batch *commands
|
@@ -6,7 +6,7 @@ describe Neography::Rest do
|
|
6
6
|
end
|
7
7
|
|
8
8
|
describe "don't break gremlin" do
|
9
|
-
it "can handle node and relationship indexes" do
|
9
|
+
it "can handle node and relationship indexes", :gremlin => true do
|
10
10
|
new_node1 = @neo.create_node
|
11
11
|
new_node2 = @neo.create_node
|
12
12
|
new_relationship = @neo.create_relationship("friends", new_node1, new_node2)
|
@@ -16,7 +16,7 @@ describe Neography::Rest do
|
|
16
16
|
@neo.add_relationship_to_index("test_index2", key, value, new_relationship)
|
17
17
|
end
|
18
18
|
|
19
|
-
it "gremlin works" do
|
19
|
+
it "gremlin works", :gremlin => true do
|
20
20
|
root_node = @neo.execute_script("g.v(0)")
|
21
21
|
root_node.should have_key("self")
|
22
22
|
root_node["self"].split('/').last.should == "0"
|
@@ -25,7 +25,7 @@ describe Neography::Rest do
|
|
25
25
|
|
26
26
|
|
27
27
|
describe "break gremlin" do
|
28
|
-
it "can can't handle node and relationship indexes with the same name", :
|
28
|
+
it "can can't handle node and relationship indexes with the same name", :gremlin => true do
|
29
29
|
new_node1 = @neo.create_node
|
30
30
|
new_node2 = @neo.create_node
|
31
31
|
new_relationship = @neo.create_relationship("friends", new_node1, new_node2)
|
@@ -35,7 +35,7 @@ describe Neography::Rest do
|
|
35
35
|
@neo.add_relationship_to_index("test_index3", key, value, new_relationship)
|
36
36
|
end
|
37
37
|
|
38
|
-
it "gremlin works" do
|
38
|
+
it "gremlin works", :gremlin => true do
|
39
39
|
root_node = @neo.execute_script("g.v(0)")
|
40
40
|
root_node.should have_key("self")
|
41
41
|
root_node["self"].split('/').last.should == "0"
|
@@ -8,7 +8,7 @@ describe Neography::Connection do
|
|
8
8
|
|
9
9
|
it "should add a content type if there's existing headers" do
|
10
10
|
subject.merge_options({:headers => {'Content-Type' => 'foo/bar'}})[:headers].should ==
|
11
|
-
{'Content-Type' => "foo/bar", "User-Agent" => "Neography/#{Neography::VERSION}"}
|
11
|
+
{'Content-Type' => "foo/bar", "User-Agent" => "Neography/#{Neography::VERSION}" , "X-Stream"=>true}
|
12
12
|
end
|
13
13
|
|
14
14
|
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Neography::Rest do
|
4
|
+
before(:each) do
|
5
|
+
@neo = Neography::Rest.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "list_labels" do
|
9
|
+
it "can get the labels of the database" do
|
10
|
+
@neo.set_label(0, "Person")
|
11
|
+
labels = @neo.list_labels
|
12
|
+
labels.should include("Person")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "add_label" do
|
17
|
+
it "can add a label to a node" do
|
18
|
+
new_node = @neo.create_node
|
19
|
+
new_node_id = new_node["self"].split('/').last
|
20
|
+
@neo.add_label(new_node_id, "Person")
|
21
|
+
labels = @neo.get_node_labels(new_node_id)
|
22
|
+
labels.should == ["Person"]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can add another label to a node" do
|
26
|
+
new_node = @neo.create_node
|
27
|
+
new_node_id = new_node["self"].split('/').last
|
28
|
+
@neo.add_label(new_node_id, "Actor")
|
29
|
+
@neo.add_label(new_node_id, "Director")
|
30
|
+
labels = @neo.get_node_labels(new_node_id)
|
31
|
+
labels.should == ["Actor", "Director"]
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can add multiple labels to a node" do
|
35
|
+
new_node = @neo.create_node
|
36
|
+
new_node_id = new_node["self"].split('/').last
|
37
|
+
@neo.add_label(new_node_id, ["Actor", "Director"])
|
38
|
+
labels = @neo.get_node_labels(new_node_id)
|
39
|
+
labels.should == ["Actor", "Director"]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "set_label" do
|
44
|
+
it "can set a label to a node" do
|
45
|
+
new_node = @neo.create_node
|
46
|
+
new_node_id = new_node["self"].split('/').last
|
47
|
+
@neo.set_label(new_node_id, "Person")
|
48
|
+
labels = @neo.get_node_labels(new_node_id)
|
49
|
+
labels.should == ["Person"]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "can set a label to a node that already had a label" do
|
53
|
+
new_node = @neo.create_node
|
54
|
+
new_node_id = new_node["self"].split('/').last
|
55
|
+
@neo.add_label(new_node_id, "Actor")
|
56
|
+
@neo.set_label(new_node_id, "Director")
|
57
|
+
labels = @neo.get_node_labels(new_node_id)
|
58
|
+
labels.should == ["Director"]
|
59
|
+
end
|
60
|
+
|
61
|
+
it "can set multiple labels to a node" do
|
62
|
+
new_node = @neo.create_node
|
63
|
+
new_node_id = new_node["self"].split('/').last
|
64
|
+
@neo.set_label(new_node_id, ["Actor", "Director"])
|
65
|
+
labels = @neo.get_node_labels(new_node_id)
|
66
|
+
labels.should == ["Actor", "Director"]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "delete_label" do
|
71
|
+
it "can delete a label from a node" do
|
72
|
+
new_node = @neo.create_node
|
73
|
+
new_node_id = new_node["self"].split('/').last
|
74
|
+
@neo.set_label(new_node_id, ["Actor", "Director"])
|
75
|
+
@neo.delete_label(new_node_id, "Actor")
|
76
|
+
labels = @neo.get_node_labels(new_node_id)
|
77
|
+
labels.should == ["Director"]
|
78
|
+
end
|
79
|
+
|
80
|
+
it "can delete a label from a node that doesn't have one" do
|
81
|
+
new_node = @neo.create_node
|
82
|
+
new_node_id = new_node["self"].split('/').last
|
83
|
+
@neo.delete_label(new_node_id, "Actor")
|
84
|
+
labels = @neo.get_node_labels(new_node_id)
|
85
|
+
labels.should == []
|
86
|
+
end
|
87
|
+
|
88
|
+
it "cannot delete a label from a node that doesn't exist" do
|
89
|
+
new_node = @neo.create_node
|
90
|
+
new_node_id = new_node["self"].split('/').last
|
91
|
+
expect {
|
92
|
+
@neo.delete_label(new_node_id.to_i + 1, "Actor")
|
93
|
+
}.to raise_error Neography::NodeNotFoundException
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "get_nodes_labeled" do
|
98
|
+
it "can get a node with a label" do
|
99
|
+
new_node = @neo.create_node
|
100
|
+
new_node_id = new_node["self"].split('/').last
|
101
|
+
@neo.set_label(new_node_id, ["Actor", "Director"])
|
102
|
+
nodes = @neo.get_nodes_labeled("Actor")
|
103
|
+
nodes.last["self"].split('/').last.should == new_node_id
|
104
|
+
end
|
105
|
+
|
106
|
+
it "returns an empty array on non-existing label" do
|
107
|
+
nodes = @neo.get_nodes_labeled("do_not_exist")
|
108
|
+
nodes.should == []
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "find_nodes_labeled" do
|
113
|
+
it "can find a node with a label and a property" do
|
114
|
+
new_node = @neo.create_node(:name => "max")
|
115
|
+
new_node_id = new_node["self"].split('/').last
|
116
|
+
@neo.set_label(new_node_id, "clown")
|
117
|
+
nodes = @neo.find_nodes_labeled("clown", { :name => "max" })
|
118
|
+
nodes.last["self"].split('/').last.should == new_node_id
|
119
|
+
end
|
120
|
+
|
121
|
+
it "returns an empty array on non-existing label property" do
|
122
|
+
new_node = @neo.create_node(:name => "max")
|
123
|
+
new_node_id = new_node["self"].split('/').last
|
124
|
+
@neo.set_label(new_node_id, "clown")
|
125
|
+
nodes = @neo.find_nodes_labeled("clown", { :name => "does_not_exist" })
|
126
|
+
nodes.should == []
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|