neography 0.0.31 → 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.
Files changed (85) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +1 -1
  3. data/CONTRIBUTORS +2 -1
  4. data/README.md +247 -0
  5. data/Rakefile +1 -2
  6. data/lib/neography/config.rb +48 -16
  7. data/lib/neography/connection.rb +151 -0
  8. data/lib/neography/errors.rb +42 -0
  9. data/lib/neography/node.rb +17 -14
  10. data/lib/neography/node_relationship.rb +3 -1
  11. data/lib/neography/node_traverser.rb +24 -20
  12. data/lib/neography/property.rb +31 -28
  13. data/lib/neography/property_container.rb +1 -1
  14. data/lib/neography/relationship.rb +16 -19
  15. data/lib/neography/rest/auto_indexes.rb +64 -0
  16. data/lib/neography/rest/batch.rb +262 -0
  17. data/lib/neography/rest/clean.rb +19 -0
  18. data/lib/neography/rest/cypher.rb +24 -0
  19. data/lib/neography/rest/gremlin.rb +24 -0
  20. data/lib/neography/rest/helpers.rb +26 -0
  21. data/lib/neography/rest/indexes.rb +97 -0
  22. data/lib/neography/rest/node_auto_indexes.rb +14 -0
  23. data/lib/neography/rest/node_indexes.rb +35 -0
  24. data/lib/neography/rest/node_paths.rb +57 -0
  25. data/lib/neography/rest/node_properties.rb +11 -0
  26. data/lib/neography/rest/node_relationships.rb +53 -0
  27. data/lib/neography/rest/node_traversal.rb +81 -0
  28. data/lib/neography/rest/nodes.rb +102 -0
  29. data/lib/neography/rest/paths.rb +36 -0
  30. data/lib/neography/rest/properties.rb +56 -0
  31. data/lib/neography/rest/relationship_auto_indexes.rb +14 -0
  32. data/lib/neography/rest/relationship_indexes.rb +35 -0
  33. data/lib/neography/rest/relationship_properties.rb +11 -0
  34. data/lib/neography/rest/relationships.rb +23 -0
  35. data/lib/neography/rest.rb +285 -615
  36. data/lib/neography/tasks.rb +1 -1
  37. data/lib/neography/version.rb +1 -1
  38. data/lib/neography.rb +13 -2
  39. data/neography.gemspec +8 -8
  40. data/spec/integration/authorization_spec.rb +2 -2
  41. data/spec/integration/index_spec.rb +4 -4
  42. data/spec/integration/neography_spec.rb +2 -2
  43. data/spec/integration/node_path_spec.rb +2 -2
  44. data/spec/integration/node_relationship_spec.rb +5 -3
  45. data/spec/integration/node_spec.rb +20 -19
  46. data/spec/integration/parsing_spec.rb +2 -2
  47. data/spec/integration/relationship_spec.rb +2 -2
  48. data/spec/integration/rest_batch_spec.rb +28 -28
  49. data/spec/integration/rest_bulk_spec.rb +2 -2
  50. data/spec/integration/rest_experimental_spec.rb +2 -2
  51. data/spec/integration/rest_gremlin_fail_spec.rb +2 -2
  52. data/spec/integration/rest_header_spec.rb +4 -9
  53. data/spec/integration/rest_index_spec.rb +21 -1
  54. data/spec/integration/rest_node_spec.rb +58 -44
  55. data/spec/integration/rest_path_spec.rb +5 -5
  56. data/spec/integration/rest_plugin_spec.rb +8 -2
  57. data/spec/integration/rest_relationship_spec.rb +35 -30
  58. data/spec/integration/rest_traverse_spec.rb +2 -2
  59. data/spec/matchers.rb +33 -0
  60. data/spec/neography_spec.rb +23 -0
  61. data/spec/spec_helper.rb +19 -1
  62. data/spec/unit/config_spec.rb +46 -0
  63. data/spec/unit/connection_spec.rb +205 -0
  64. data/spec/unit/node_spec.rb +100 -0
  65. data/spec/unit/properties_spec.rb +136 -0
  66. data/spec/unit/relationship_spec.rb +118 -0
  67. data/spec/unit/rest/batch_spec.rb +243 -0
  68. data/spec/unit/rest/clean_spec.rb +17 -0
  69. data/spec/unit/rest/cypher_spec.rb +21 -0
  70. data/spec/unit/rest/gremlin_spec.rb +26 -0
  71. data/spec/unit/rest/node_auto_indexes_spec.rb +67 -0
  72. data/spec/unit/rest/node_indexes_spec.rb +126 -0
  73. data/spec/unit/rest/node_paths_spec.rb +80 -0
  74. data/spec/unit/rest/node_properties_spec.rb +80 -0
  75. data/spec/unit/rest/node_relationships_spec.rb +78 -0
  76. data/spec/unit/rest/node_traversal_spec.rb +128 -0
  77. data/spec/unit/rest/nodes_spec.rb +188 -0
  78. data/spec/unit/rest/paths_spec.rb +69 -0
  79. data/spec/unit/rest/relationship_auto_indexes_spec.rb +67 -0
  80. data/spec/unit/rest/relationship_indexes_spec.rb +128 -0
  81. data/spec/unit/rest/relationship_properties_spec.rb +80 -0
  82. data/spec/unit/rest/relationships_spec.rb +22 -0
  83. metadata +86 -19
  84. data/Gemfile.lock +0 -44
  85. data/README.rdoc +0 -420
@@ -0,0 +1,205 @@
1
+ require 'spec_helper'
2
+
3
+ module Neography
4
+ describe Connection do
5
+
6
+ subject(:connection)
7
+
8
+ context "defaults" do
9
+
10
+ it "intializes with defaults" do
11
+ connection.configuration.should == "http://localhost:7474/db/data"
12
+ end
13
+
14
+ end
15
+
16
+ context "custom options" do
17
+
18
+ subject(:connection) { Connection.new(options) }
19
+
20
+ context "hash options" do
21
+ let(:options) do
22
+ {
23
+ :protocol => "https://",
24
+ :server => "foobar",
25
+ :port => 4242,
26
+ :directory => "/dir",
27
+ :cypher_path => "/cyph",
28
+ :gremlin_path => "/grem",
29
+ :log_file => "neo.log",
30
+ :log_enabled => false,
31
+ :max_threads => 10,
32
+ :parser => Foo,
33
+ :authentication => "foo",
34
+ :username => "bar",
35
+ :password => "baz"
36
+ }
37
+ end
38
+
39
+ it "accepts all options in a hash" do
40
+ connection.configuration.should == "https://foobar:4242/dir/db/data"
41
+
42
+ connection.protocol.should == "https://"
43
+ connection.server.should == "foobar"
44
+ connection.port.should == 4242
45
+ connection.directory.should == "/dir"
46
+ connection.cypher_path.should == "/cyph"
47
+ connection.gremlin_path.should == "/grem"
48
+ connection.log_file.should == "neo.log"
49
+ connection.log_enabled.should == false
50
+ connection.max_threads.should == 10
51
+ connection.parser.should == Foo
52
+
53
+ connection.authentication.should == {
54
+ :foo_auth => {
55
+ :username => "bar",
56
+ :password => "baz"
57
+ }
58
+ }
59
+ end
60
+ end
61
+
62
+ context "string option" do
63
+ let(:options) { "https://user:pass@somehost:8585/path" }
64
+
65
+ it "accepts a string as configuration" do
66
+ connection.configuration.should == "https://somehost:8585/path/db/data"
67
+ connection.authentication.should == {
68
+ :basic_auth => {
69
+ :username => "user",
70
+ :password => "pass"
71
+ }
72
+ }
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+ context "requests" do
79
+
80
+ it "does a GET request" do
81
+ HTTParty.should_receive(:get).with("http://localhost:7474/db/data/foo/bar", { :parser => MultiJsonParser }) { stub.as_null_object }
82
+ connection.get("/foo/bar")
83
+ end
84
+
85
+ it "does a POST request" do
86
+ HTTParty.should_receive(:post).with("http://localhost:7474/db/data/foo/bar", { :parser => MultiJsonParser }) { stub.as_null_object }
87
+ connection.post("/foo/bar")
88
+ end
89
+
90
+ it "does a PUT request" do
91
+ HTTParty.should_receive(:put).with("http://localhost:7474/db/data/foo/bar", { :parser => MultiJsonParser }) { stub.as_null_object }
92
+ connection.put("/foo/bar")
93
+ end
94
+
95
+ it "does a DELETE request" do
96
+ HTTParty.should_receive(:delete).with("http://localhost:7474/db/data/foo/bar", { :parser => MultiJsonParser }) { stub.as_null_object }
97
+ connection.delete("/foo/bar")
98
+ end
99
+
100
+ context "authentication" do
101
+ subject(:connection) do
102
+ Connection.new({
103
+ :authentication => "basic",
104
+ :username => "foo",
105
+ :password => "bar"
106
+ })
107
+ end
108
+
109
+ it "does requests with authentication" do
110
+ HTTParty.should_receive(:get).with(
111
+ "http://localhost:7474/db/data/foo/bar",
112
+ { :parser => MultiJsonParser,
113
+ :basic_auth => {
114
+ :username => "foo",
115
+ :password => "bar"
116
+ }
117
+ }) { stub.as_null_object }
118
+
119
+ connection.get("/foo/bar")
120
+ end
121
+ end
122
+
123
+ it "adds the User-Agent to the headers" do
124
+ HTTParty.should_receive(:get).with(
125
+ "http://localhost:7474/db/data/foo/bar",
126
+ { :parser => MultiJsonParser,
127
+ :headers => { "User-Agent" => "Neography/#{Neography::VERSION}" }
128
+ }) { stub.as_null_object }
129
+
130
+ connection.get("/foo/bar", :headers => {})
131
+ end
132
+
133
+ context "errors" do
134
+
135
+ it "raises NodeNotFoundException" do
136
+ response = error_response(code: 404, message: "a message", exception: "NodeNotFoundException")
137
+ HTTParty.stub(:get).and_return(response)
138
+ expect {
139
+ connection.get("/foo/bar")
140
+ }.to raise_error NodeNotFoundException
141
+ end
142
+
143
+ it "raises OperationFailureException" do
144
+ response = error_response(code: 409, message: "a message", exception: "OperationFailureException")
145
+ HTTParty.stub(:get).and_return(response)
146
+ expect {
147
+ connection.get("/foo/bar")
148
+ }.to raise_error OperationFailureException
149
+ end
150
+
151
+ it "raises PropertyValueException" do
152
+ response = error_response(code: 400, message: "a message", exception: "PropertyValueException")
153
+ HTTParty.stub(:get).and_return(response)
154
+ expect {
155
+ connection.get("/foo/bar")
156
+ }.to raise_error PropertyValueException
157
+ end
158
+
159
+ it "raises NoSuchPropertyException" do
160
+ response = error_response(code: 404, message: "a message", exception: "NoSuchPropertyException")
161
+ HTTParty.stub(:get).and_return(response)
162
+ expect {
163
+ connection.get("/foo/bar")
164
+ }.to raise_error NoSuchPropertyException
165
+ end
166
+
167
+ it "raises RelationshipNotFoundException" do
168
+ response = error_response(code: 404, message: "a message", exception: "RelationshipNotFoundException")
169
+ HTTParty.stub(:get).and_return(response)
170
+ expect {
171
+ connection.get("/foo/bar")
172
+ }.to raise_error RelationshipNotFoundException
173
+ end
174
+
175
+ it "raises BadInputException" do
176
+ response = error_response(code: 400, message: "a message", exception: "BadInputException")
177
+ HTTParty.stub(:get).and_return(response)
178
+ expect {
179
+ connection.get("/foo/bar")
180
+ }.to raise_error BadInputException
181
+ end
182
+
183
+ it "raises UnauthorizedError" do
184
+ response = error_response(code: 401)
185
+ HTTParty.stub(:get).and_return(response)
186
+ expect {
187
+ connection.get("/foo/bar")
188
+ }.to raise_error UnauthorizedError
189
+ end
190
+
191
+ it "raises NeographyError in all other cases" do
192
+ response = error_response(code: 418, message: "I'm a teapot.")
193
+ HTTParty.stub(:get).and_return(response)
194
+ expect {
195
+ connection.get("/foo/bar")
196
+ }.to raise_error NeographyError
197
+ end
198
+
199
+ end
200
+
201
+ end
202
+ end
203
+ end
204
+
205
+ class Foo; end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+
3
+ module Neography
4
+ describe Node do
5
+
6
+ describe "::create" do
7
+ context "no explicit server" do
8
+
9
+ before do
10
+ @db = mock(Neography::Rest, :is_a? => true).as_null_object
11
+ Rest.stub(:new) { @db }
12
+ end
13
+
14
+ it "assigns a new Rest db by default" do
15
+ node = Node.create
16
+ node.neo_server.should == @db
17
+ end
18
+
19
+ it "creates without arguments" do
20
+ @db.should_receive(:create_node).with(nil)
21
+ Node.create
22
+ end
23
+
24
+ it "creates with only a hash argument" do
25
+ properties = { :foo => "bar" }
26
+ @db.should_receive(:create_node).with(properties)
27
+ Node.create(properties)
28
+ end
29
+
30
+ end
31
+
32
+ context "explicit server" do
33
+
34
+ it "cannot pass a server as the first argument, properties as the second (deprecated)" do
35
+ @other_server = Neography::Rest.new
36
+ properties = { :foo => "bar" }
37
+ @other_server.should_not_receive(:create_node).with(properties)
38
+ expect {
39
+ Node.create(@other_server, properties)
40
+ }.to raise_error(ArgumentError)
41
+ end
42
+
43
+ it "can pass properties as the first argument, a server as the second" do
44
+ @other_server = Neography::Rest.new
45
+ properties = { :foo => "bar" }
46
+ @other_server.should_receive(:create_node).with(properties)
47
+ Node.create(properties, @other_server)
48
+ end
49
+
50
+ end
51
+ end
52
+
53
+ describe "::load" do
54
+ context "no explicit server" do
55
+
56
+ before do
57
+ # stub out actual connections
58
+ @db = stub(Rest).as_null_object
59
+ Rest.stub(:new) { @db }
60
+ end
61
+
62
+ it "load by id" do
63
+ @db.should_receive(:get_node).with(5)
64
+ Node.load(5)
65
+ end
66
+
67
+ it "loads by node" do
68
+ node = Node.new
69
+ @db.should_receive(:get_node).with(node)
70
+ Node.load(node)
71
+ end
72
+
73
+ it "loads by full server string" do
74
+ @db.should_receive(:get_node).with("http://localhost:7474/db/data/node/2")
75
+ Node.load("http://localhost:7474/db/data/node/2")
76
+ end
77
+
78
+ end
79
+
80
+ context "explicit server" do
81
+
82
+ it "cannot pass a server as the first argument, node as the second (depracted)" do
83
+ @other_server = Neography::Rest.new
84
+ @other_server.should_not_receive(:get_node).with(42)
85
+ expect {
86
+ node = Node.load(@other_server, 42)
87
+ }.to raise_error(ArgumentError)
88
+ end
89
+
90
+ it "can pass a node as the first argument, server as the second" do
91
+ @other_server = Neography::Rest.new
92
+ @other_server.should_receive(:get_node).with(42)
93
+ node = Node.load(42, @other_server)
94
+ end
95
+
96
+ end
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,136 @@
1
+ require 'spec_helper'
2
+
3
+ module Neography
4
+ describe "Properties" do
5
+
6
+ before do
7
+ @db = mock(Neography::Rest, :is_a? => true).as_null_object
8
+ Rest.stub(:new) { @db }
9
+ end
10
+
11
+ context "Node" do
12
+
13
+ subject(:node) do
14
+ node = Node.create
15
+ node.stub(:neo_id => 42)
16
+ node
17
+ end
18
+
19
+ it "sets properties as accessor" do
20
+ @db.should_receive(:"set_node_properties").with(42, { "key" => "value" })
21
+ node.key = "value"
22
+ end
23
+
24
+ it "sets properties as array entry" do
25
+ @db.should_receive(:"set_node_properties").with(42, { "key" => "value" })
26
+ node["key"] = "value"
27
+ end
28
+
29
+ it "gets properties as accessor" do
30
+ @db.stub(:"set_node_properties")
31
+ node.key = "value"
32
+ node.key.should == "value"
33
+ end
34
+
35
+ it "gets properties as array entry" do
36
+ @db.stub(:"set_node_properties")
37
+ node["key"] = "value"
38
+ node["key"].should == "value"
39
+ end
40
+
41
+ it "resets properties as accessor" do
42
+ @db.should_receive(:"remove_node_properties").with(42, ["key"])
43
+ node.key = nil
44
+ end
45
+
46
+ it "resets properties as array entry" do
47
+ @db.should_receive(:"remove_node_properties").with(42, ["key"])
48
+ node["key"] = nil
49
+ end
50
+
51
+ it "gets unknown properties as nil" do
52
+ node.unknown.should == nil
53
+ end
54
+
55
+ it "overwrites existing properties" do
56
+ @db.should_receive(:"set_node_properties").with(42, { "key" => "value1" })
57
+ node.key = "value1"
58
+
59
+ @db.should_receive(:"set_node_properties").with(42, { "key" => "value2" })
60
+ node.key = "value2"
61
+ end
62
+
63
+ it "knows its attributes" do
64
+ @db.stub(:"set_node_properties")
65
+ node.key = "value"
66
+ node["key2"] = "value"
67
+ node.attributes.should =~ [ :key, :key2 ]
68
+ end
69
+
70
+ end
71
+
72
+ context "Relationship" do
73
+
74
+ subject(:relationship) do
75
+ from = Node.create
76
+ to = Node.create
77
+
78
+ rel = Relationship.create(:type, from, to)
79
+ rel.stub(:neo_id => 42)
80
+ rel
81
+ end
82
+
83
+ it "sets properties as accessor" do
84
+ @db.should_receive(:"set_relationship_properties").with(42, { "key" => "value" })
85
+ relationship.key = "value"
86
+ end
87
+
88
+ it "sets properties as array entry" do
89
+ @db.should_receive(:"set_relationship_properties").with(42, { "key" => "value" })
90
+ relationship["key"] = "value"
91
+ end
92
+
93
+ it "gets properties as accessor" do
94
+ @db.stub(:"set_relationship_properties")
95
+ relationship.key = "value"
96
+ relationship.key.should == "value"
97
+ end
98
+
99
+ it "gets properties as array entry" do
100
+ @db.stub(:"set_relationship_properties")
101
+ relationship["key"] = "value"
102
+ relationship["key"].should == "value"
103
+ end
104
+
105
+ it "resets properties as accessor" do
106
+ @db.should_receive(:"remove_relationship_properties").with(42, ["key"])
107
+ relationship.key = nil
108
+ end
109
+
110
+ it "resets properties as array entry" do
111
+ @db.should_receive(:"remove_relationship_properties").with(42, ["key"])
112
+ relationship["key"] = nil
113
+ end
114
+
115
+ it "gets unknown properties as nil" do
116
+ relationship.unknown.should == nil
117
+ end
118
+
119
+ it "overwrites existing properties" do
120
+ @db.should_receive(:"set_relationship_properties").with(42, { "key" => "value1" })
121
+ relationship.key = "value1"
122
+
123
+ @db.should_receive(:"set_relationship_properties").with(42, { "key" => "value2" })
124
+ relationship.key = "value2"
125
+ end
126
+
127
+ it "knows its attributes" do
128
+ @db.stub(:"set_relationship_properties")
129
+ relationship.key = "value"
130
+ relationship["key2"] = "value"
131
+ relationship.attributes.should =~ [ :key, :key2 ]
132
+ end
133
+
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+
3
+ module Neography
4
+ describe Relationship do
5
+
6
+ let(:db) { stub(Rest).as_null_object }
7
+ let(:relationship_hash) do
8
+ {
9
+ "self" => "0",
10
+ "start" => "1",
11
+ "end" => "2",
12
+ "data" => {}
13
+ }
14
+ end
15
+
16
+ let(:from) { stub(:neo_server => db) }
17
+ let(:to) { stub(:neo_server => db) }
18
+ let(:props) { { :foo => "bar" } }
19
+
20
+ describe "::create" do
21
+ it "creates a new node through Rest" do
22
+ db.should_receive(:create_relationship).with("type", from, to, props)
23
+
24
+ Relationship.create("type", from, to, props)
25
+ end
26
+
27
+ it "assigns fields" do
28
+ db.stub(:create_relationship).and_return(relationship_hash)
29
+
30
+ rel = Relationship.create("type", from, to, props)
31
+
32
+ rel.start_node.should == from
33
+ rel.end_node.should == to
34
+ rel.rel_type.should == "type"
35
+ end
36
+ end
37
+
38
+ describe "::load" do
39
+ context "no explicit server" do
40
+
41
+ before do
42
+ # stub out actual connections
43
+ @db = stub(Rest).as_null_object
44
+ Rest.stub(:new) { @db }
45
+ end
46
+
47
+ it "load by id" do
48
+ @db.should_receive(:get_relationship).with(5)
49
+ Relationship.load(5)
50
+ end
51
+
52
+ it "loads by relationship" do
53
+ relationship = Relationship.new(relationship_hash)
54
+ @db.should_receive(:get_relationship).with(relationship)
55
+ Relationship.load(relationship)
56
+ end
57
+
58
+ it "loads by full server string" do
59
+ @db.should_receive(:get_relationship).with("http://localhost:7474/db/data/relationship/2")
60
+ Relationship.load("http://localhost:7474/db/data/relationship/2")
61
+ end
62
+
63
+ end
64
+
65
+ context "explicit server" do
66
+
67
+ it "cannot pass a server as the first argument, relationship as the second" do
68
+ @other_server = Neography::Rest.new
69
+ @other_server.should_not_receive(:get_relationship).with(42)
70
+ expect {
71
+ relationship = Relationship.load(@other_server, 42)
72
+ }.to raise_error(ArgumentError)
73
+ end
74
+
75
+ it "can pass a relationship as the first argument, server as the second" do
76
+ @other_server = Neography::Rest.new
77
+ @other_server.should_receive(:get_relationship).with(42)
78
+ relationship = Relationship.load(42, @other_server)
79
+ end
80
+
81
+ end
82
+ end
83
+
84
+ describe "#del" do
85
+
86
+ before do
87
+ db.stub(:create_relationship) { relationship_hash }
88
+ end
89
+
90
+ subject(:relationship) { Relationship.create("type", from, to, props) }
91
+
92
+ it "deletes a node" do
93
+ db.should_receive(:delete_relationship).with("0")
94
+ relationship.del
95
+ end
96
+
97
+ end
98
+
99
+ describe "#other_node" do
100
+
101
+ before do
102
+ db.stub(:create_relationship) { relationship_hash }
103
+ end
104
+
105
+ subject(:relationship) { Relationship.create("type", from, to, props) }
106
+
107
+ it "knows the other node based on from" do
108
+ relationship.other_node(from).should == to
109
+ end
110
+
111
+ it "knows the other node based on to" do
112
+ relationship.other_node(to).should == from
113
+ end
114
+
115
+ end
116
+
117
+ end
118
+ end