neography 1.4.1 → 1.5.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 +4 -4
- data/ChangeLog +5 -0
- data/lib/neography.rb +1 -1
- data/lib/neography/config.rb +38 -34
- data/lib/neography/connection.rb +53 -32
- data/lib/neography/errors.rb +3 -0
- data/lib/neography/rest/batch.rb +16 -6
- data/lib/neography/rest/node_auto_indexes.rb +1 -1
- data/lib/neography/rest/node_indexes.rb +16 -2
- data/lib/neography/rest/relationship_indexes.rb +16 -2
- data/lib/neography/tasks.rb +1 -2
- data/lib/neography/version.rb +1 -1
- data/neography.gemspec +1 -1
- data/spec/integration/rest_batch_no_streaming_spec.rb +41 -0
- data/spec/integration/rest_batch_spec.rb +14 -0
- data/spec/integration/rest_batch_streaming_spec.rb +22 -3
- data/spec/integration/rest_index_spec.rb +4 -1
- data/spec/spec_helper.rb +1 -2
- data/spec/unit/config_spec.rb +39 -34
- data/spec/unit/connection_spec.rb +75 -50
- data/spec/unit/rest/node_auto_indexes_spec.rb +4 -0
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae76679128738baf8ce0f7e770abda5aab5f5391
|
4
|
+
data.tar.gz: e1da52e3ce0cf1f8182cdb5dc109b70ffb084487
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94a8a3375f463c3cf7d036f8d06f82e15971dfc3723cff255701d135d634d42ad31128c3839d58b09defa92723e0563898925f16298ee8fd548abfa19589a3f5
|
7
|
+
data.tar.gz: ca5a8a40e7fca44bd8c478eb3e6f1a6e4254dbdd55737156224a85aad6dd3c712c5a53ca27495d352aacbc1182f0cfb37649abee31048d6f36473fca7d721a6f
|
data/ChangeLog
CHANGED
data/lib/neography.rb
CHANGED
data/lib/neography/config.rb
CHANGED
@@ -7,7 +7,7 @@ module Neography
|
|
7
7
|
:max_threads,
|
8
8
|
:authentication, :username, :password,
|
9
9
|
:parser, :max_execution_time,
|
10
|
-
:proxy
|
10
|
+
:proxy, :http_send_timeout, :http_receive_timeout
|
11
11
|
|
12
12
|
def initialize
|
13
13
|
set_defaults
|
@@ -15,45 +15,49 @@ module Neography
|
|
15
15
|
|
16
16
|
def to_hash
|
17
17
|
{
|
18
|
-
:protocol
|
19
|
-
:server
|
20
|
-
:port
|
21
|
-
:directory
|
22
|
-
:cypher_path
|
23
|
-
:gremlin_path
|
24
|
-
:log_file
|
25
|
-
:log_enabled
|
26
|
-
:logger
|
27
|
-
:slow_log_threshold
|
28
|
-
:max_threads
|
29
|
-
:authentication
|
30
|
-
:username
|
31
|
-
:password
|
32
|
-
:parser
|
33
|
-
:max_execution_time
|
34
|
-
:proxy
|
18
|
+
:protocol => @protocol,
|
19
|
+
:server => @server,
|
20
|
+
:port => @port,
|
21
|
+
:directory => @directory,
|
22
|
+
:cypher_path => @cypher_path,
|
23
|
+
:gremlin_path => @gremlin_path,
|
24
|
+
:log_file => @log_file,
|
25
|
+
:log_enabled => @log_enabled,
|
26
|
+
:logger => @logger,
|
27
|
+
:slow_log_threshold => @slow_log_threshold,
|
28
|
+
:max_threads => @max_threads,
|
29
|
+
:authentication => @authentication,
|
30
|
+
:username => @username,
|
31
|
+
:password => @password,
|
32
|
+
:parser => @parser,
|
33
|
+
:max_execution_time => @max_execution_time,
|
34
|
+
:proxy => @proxy,
|
35
|
+
:http_send_timeout => @http_send_timeout,
|
36
|
+
:http_receive_timeout => @http_receive_timeout
|
35
37
|
}
|
36
38
|
end
|
37
39
|
|
38
40
|
private
|
39
41
|
|
40
42
|
def set_defaults
|
41
|
-
@protocol
|
42
|
-
@server
|
43
|
-
@port
|
44
|
-
@directory
|
45
|
-
@cypher_path
|
46
|
-
@gremlin_path
|
47
|
-
@log_file
|
48
|
-
@log_enabled
|
49
|
-
@slow_log_threshold
|
50
|
-
@max_threads
|
51
|
-
@authentication
|
52
|
-
@username
|
53
|
-
@password
|
54
|
-
@parser
|
55
|
-
@max_execution_time
|
56
|
-
@proxy
|
43
|
+
@protocol = "http://"
|
44
|
+
@server = "localhost"
|
45
|
+
@port = 7474
|
46
|
+
@directory = ""
|
47
|
+
@cypher_path = "/cypher"
|
48
|
+
@gremlin_path = "/ext/GremlinPlugin/graphdb/execute_script"
|
49
|
+
@log_file = "neography.log"
|
50
|
+
@log_enabled = false
|
51
|
+
@slow_log_threshold = 0
|
52
|
+
@max_threads = 20
|
53
|
+
@authentication = nil
|
54
|
+
@username = nil
|
55
|
+
@password = nil
|
56
|
+
@parser = MultiJsonParser
|
57
|
+
@max_execution_time = 6000
|
58
|
+
@proxy = nil
|
59
|
+
@http_send_timeout = 1200
|
60
|
+
@http_receive_timeout = 1200
|
57
61
|
end
|
58
62
|
|
59
63
|
end
|
data/lib/neography/connection.rb
CHANGED
@@ -4,22 +4,25 @@ module Neography
|
|
4
4
|
class Connection
|
5
5
|
USER_AGENT = "Neography/#{Neography::VERSION}"
|
6
6
|
ACTIONS = ["get", "post", "put", "delete"]
|
7
|
-
|
8
|
-
|
7
|
+
|
8
|
+
attr_reader :protocol, :server, :port, :directory,
|
9
9
|
:cypher_path, :gremlin_path,
|
10
10
|
:log_file, :log_enabled, :logger, :slow_log_threshold,
|
11
11
|
:max_threads,
|
12
12
|
:authentication, :username, :password,
|
13
13
|
:parser, :client,
|
14
|
-
:proxy
|
14
|
+
:proxy, :http_send_timeout, :http_receive_timeout
|
15
15
|
|
16
16
|
def initialize(options = ENV['NEO4J_URL'] || {})
|
17
17
|
config = merge_configuration(options)
|
18
18
|
save_local_configuration(config)
|
19
|
-
@client ||=
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
@client ||= Excon.new(config[:proxy] || "#{@protocol}#{@server}:#{@port}",
|
20
|
+
:read_timeout => config[:http_receive_timeout],
|
21
|
+
:write_timeout => config[:http_send_timeout],
|
22
|
+
:persistent => true,
|
23
|
+
:user => config[:username],
|
24
|
+
:password => config[:password])
|
25
|
+
#authenticate
|
23
26
|
end
|
24
27
|
|
25
28
|
def configure(protocol, server, port, directory)
|
@@ -35,23 +38,39 @@ module Neography
|
|
35
38
|
|
36
39
|
def merge_options(options)
|
37
40
|
merged_options = options.merge!(@authentication)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
+
if merged_options[:headers]
|
42
|
+
merged_options[:headers].merge!(@user_agent)
|
43
|
+
merged_options[:headers].merge!('X-Stream' => true) unless merged_options[:headers].key?('X-Stream')
|
44
|
+
merged_options[:headers].merge!(@max_execution_time)
|
45
|
+
end
|
41
46
|
merged_options
|
42
47
|
end
|
43
48
|
|
44
49
|
ACTIONS.each do |action|
|
45
|
-
define_method(action) do |path, options = {}|
|
50
|
+
define_method(action) do |path, options = {}|
|
46
51
|
# This ugly hack is required because internal Batch paths do not start with "/db/data"
|
47
52
|
# if somebody has a cleaner solution... pull request please!
|
48
|
-
|
49
|
-
|
50
|
-
|
53
|
+
partial_path = path.split("/")
|
54
|
+
if partial_path.size > 0
|
55
|
+
partial_path = partial_path[1].split("?").first
|
56
|
+
end
|
57
|
+
reserved = ["node", "relationship", "transaction", "cypher", "propertykeys", "schema", "label", "labels", "batch", "index", "ext"]
|
58
|
+
path = "/db/data" + path if reserved.include?(partial_path)
|
59
|
+
query_body = options[:body]
|
60
|
+
stream = ""
|
61
|
+
headers = merge_options(options)[:headers]
|
51
62
|
log path, query_body do
|
52
|
-
|
63
|
+
req_params = {:method => action.to_sym, :path => path, :body => query_body, :headers => headers}
|
64
|
+
is_streaming = headers && (headers['X-Stream'] == true)
|
65
|
+
if is_streaming
|
66
|
+
streamer = lambda { |chunk, _, _| stream += chunk }
|
67
|
+
req_params.merge!({:persistent => false, :response_block => streamer,
|
68
|
+
:read_timeout => 100000000, :write_timeout => 100000000})
|
69
|
+
end
|
70
|
+
response = @client.request(req_params)
|
71
|
+
evaluate_response(response, path, query_body, is_streaming, (partial_path == "batch"), stream)
|
53
72
|
end
|
54
|
-
end
|
73
|
+
end
|
55
74
|
end
|
56
75
|
|
57
76
|
def log(path, body)
|
@@ -80,7 +99,7 @@ module Neography
|
|
80
99
|
@client.www_auth.basic_auth.challenge(configuration) if auth_type == 'basic_auth'
|
81
100
|
end
|
82
101
|
end
|
83
|
-
|
102
|
+
|
84
103
|
private
|
85
104
|
|
86
105
|
def merge_configuration(options)
|
@@ -127,29 +146,31 @@ module Neography
|
|
127
146
|
return_result(code, result)
|
128
147
|
end
|
129
148
|
|
130
|
-
def evaluate_response(response, path, query_body)
|
131
|
-
|
132
|
-
|
149
|
+
def evaluate_response(response, path, query_body, streaming, batching, stream = nil)
|
150
|
+
code = response.status
|
151
|
+
parsed = false
|
152
|
+
if streaming && batching
|
153
|
+
code, body, parsed = handle_batch(stream)
|
154
|
+
elsif streaming
|
155
|
+
body = (stream || '').force_encoding("UTF-8")
|
133
156
|
else
|
134
|
-
code = response.code
|
135
157
|
body = response.body.force_encoding("UTF-8")
|
136
|
-
parsed = false
|
137
158
|
end
|
138
159
|
return_result(response, code, body, parsed, path, query_body)
|
139
160
|
end
|
140
161
|
|
141
|
-
def handle_batch(
|
162
|
+
def handle_batch(stream)
|
142
163
|
code = 200
|
143
|
-
body = @parser.json(
|
164
|
+
body = @parser.json(stream.force_encoding("UTF-8"))
|
144
165
|
body.each do |result|
|
145
166
|
if result["status"] >= 400
|
146
|
-
code = result["status"]
|
167
|
+
code = result["status"]
|
147
168
|
break
|
148
169
|
end
|
149
170
|
end
|
150
171
|
return code, body, true
|
151
172
|
end
|
152
|
-
|
173
|
+
|
153
174
|
def return_result(response, code, body, parsed, path, query_body)
|
154
175
|
case code
|
155
176
|
when 200
|
@@ -166,7 +187,7 @@ module Neography
|
|
166
187
|
when 400..500
|
167
188
|
handle_4xx_500_response(response, code, body, path, query_body)
|
168
189
|
nil
|
169
|
-
end
|
190
|
+
end
|
170
191
|
end
|
171
192
|
|
172
193
|
def handle_4xx_500_response(response, code, body, path, query_body)
|
@@ -184,7 +205,7 @@ module Neography
|
|
184
205
|
parsed_body = result["body"] || result
|
185
206
|
break
|
186
207
|
end
|
187
|
-
end
|
208
|
+
end
|
188
209
|
else
|
189
210
|
parsed_body = @parser.json(body)
|
190
211
|
end
|
@@ -195,7 +216,7 @@ module Neography
|
|
195
216
|
@logger.error "#{response.dump} error: #{body}" if @log_enabled
|
196
217
|
raise_errors(code, parsed_body["exception"], message, stacktrace, request, index)
|
197
218
|
end
|
198
|
-
|
219
|
+
|
199
220
|
def raise_errors(code, exception, message, stacktrace, request, index)
|
200
221
|
error = nil
|
201
222
|
case code
|
@@ -215,12 +236,12 @@ module Neography
|
|
215
236
|
when /RelationshipNotFoundException/ ; RelationshipNotFoundException
|
216
237
|
when /NotFoundException/ ; NotFoundException
|
217
238
|
when /UniquePathNotUniqueException/ ; UniquePathNotUniqueException
|
218
|
-
when /DeadlockDetectedException/ ; DeadlockDetectedException
|
239
|
+
when /DeadlockDetectedException/ ; DeadlockDetectedException
|
219
240
|
else
|
220
241
|
NeographyError
|
221
242
|
end
|
222
|
-
|
223
|
-
raise error.new(message, code, stacktrace, request, index)
|
243
|
+
|
244
|
+
raise error.new(message, code, stacktrace, request, index)
|
224
245
|
end
|
225
246
|
|
226
247
|
def parse_string_options(options)
|
data/lib/neography/errors.rb
CHANGED
@@ -51,4 +51,7 @@ module Neography
|
|
51
51
|
# Signals that a deadlock between two or more transactions has been detected
|
52
52
|
class DeadlockDetectedException < NeographyError; end
|
53
53
|
|
54
|
+
# Unknown batch option exception detected
|
55
|
+
class UnknownBatchOptionException < NeographyError; end
|
56
|
+
|
54
57
|
end
|
data/lib/neography/rest/batch.rb
CHANGED
@@ -7,25 +7,35 @@ module Neography
|
|
7
7
|
do_batch(*args)
|
8
8
|
end
|
9
9
|
|
10
|
+
def batch_no_streaming(*args)
|
11
|
+
do_batch_no_streaming(*args)
|
12
|
+
end
|
13
|
+
|
10
14
|
private
|
11
15
|
|
12
16
|
def do_batch(*args)
|
17
|
+
@connection.post("/batch", compute_batch_options(*args))
|
18
|
+
end
|
19
|
+
|
20
|
+
def do_batch_no_streaming(*args)
|
21
|
+
options = compute_batch_options(*args)
|
22
|
+
options[:headers].merge!({ 'X-Stream' => false })
|
23
|
+
@connection.post("/batch", options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def compute_batch_options(*args)
|
13
27
|
batch = []
|
14
28
|
Array(args).each_with_index do |c, i|
|
15
29
|
batch << {:id => i }.merge(get_batch(c))
|
16
30
|
end
|
17
|
-
|
18
|
-
:body => batch.to_json,
|
19
|
-
:headers => json_content_type
|
20
|
-
}
|
21
|
-
@connection.post("/batch", options)
|
31
|
+
{:body => batch.to_json, :headers => json_content_type}
|
22
32
|
end
|
23
33
|
|
24
34
|
def get_batch(args)
|
25
35
|
begin
|
26
36
|
send("batch_#{args[0]}".to_sym, *args[1..-1])
|
27
37
|
rescue
|
28
|
-
raise "Unknown option #{args[0]} - #{args}"
|
38
|
+
raise UnknownBatchOptionException.new("Unknown option #{args[0]} - #{args}")
|
29
39
|
end
|
30
40
|
end
|
31
41
|
|
@@ -23,7 +23,7 @@ module Neography
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def query_node_auto_index(query_expression)
|
26
|
-
@connection.get("/index/auto/node/?query=%{query}" % {:query => query_expression}) || []
|
26
|
+
@connection.get("/index/auto/node/?query=%{query}" % {:query => encode(query_expression)}) || []
|
27
27
|
end
|
28
28
|
|
29
29
|
def get_node_auto_index_status
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Neography
|
2
2
|
class Rest
|
3
|
-
module NodeIndexes
|
3
|
+
module NodeIndexes
|
4
4
|
include Neography::Rest::Helpers
|
5
5
|
|
6
6
|
def list_node_indexes
|
@@ -117,7 +117,21 @@ module Neography
|
|
117
117
|
:headers => json_content_type
|
118
118
|
}
|
119
119
|
@connection.post("/index/node/%{index}?uniqueness=%{function}" % {:index => index, :function => 'get_or_create'}, options)
|
120
|
-
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
def create_or_fail_unique_node(index, key, value, properties = {})
|
124
|
+
options = {
|
125
|
+
:body => (
|
126
|
+
{ :properties => properties,
|
127
|
+
:key => key,
|
128
|
+
:value => value
|
129
|
+
}
|
130
|
+
).to_json,
|
131
|
+
:headers => json_content_type
|
132
|
+
}
|
133
|
+
@connection.post("/index/node/%{index}?uniqueness=%{function}" % {:index => index, :function => 'create_or_fail'}, options)
|
134
|
+
|
121
135
|
end
|
122
136
|
|
123
137
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Neography
|
2
2
|
class Rest
|
3
|
-
module RelationshipIndexes
|
3
|
+
module RelationshipIndexes
|
4
4
|
include Neography::Rest::Helpers
|
5
5
|
|
6
6
|
def list_relationship_indexes
|
@@ -118,7 +118,21 @@ module Neography
|
|
118
118
|
:headers => json_content_type
|
119
119
|
}
|
120
120
|
@connection.post("/index/relationship/%{index}?uniqueness=%{function}" % {:index => index, :function => 'get_or_create'}, options)
|
121
|
-
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
def create_or_fail_unique_relationship(index, key, value, properties = {})
|
125
|
+
options = {
|
126
|
+
:body => (
|
127
|
+
{ :properties => properties,
|
128
|
+
:key => key,
|
129
|
+
:value => value
|
130
|
+
}
|
131
|
+
).to_json,
|
132
|
+
:headers => json_content_type
|
133
|
+
}
|
134
|
+
@connection.post("/index/relationship/%{index}?uniqueness=%{function}" % {:index => index, :function => 'create_or_fail'}, options)
|
135
|
+
|
122
136
|
end
|
123
137
|
|
124
138
|
end
|
data/lib/neography/tasks.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
# borrowed from architect4r
|
2
2
|
require 'os'
|
3
|
-
require 'httpclient'
|
4
3
|
require 'zip'
|
5
4
|
require 'net/http'
|
6
5
|
|
7
6
|
namespace :neo4j do
|
8
7
|
desc "Install Neo4j"
|
9
8
|
task :install, :edition, :version do |t, args|
|
10
|
-
args.with_defaults(:edition => "community", :version => "2.0.
|
9
|
+
args.with_defaults(:edition => "community", :version => "2.0.3")
|
11
10
|
puts "Installing Neo4j-#{args[:edition]}-#{args[:version]}"
|
12
11
|
|
13
12
|
if OS::Underlying.windows?
|
data/lib/neography/version.rb
CHANGED
data/neography.gemspec
CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_development_dependency "rspec", ">= 2.11"
|
24
24
|
s.add_development_dependency "net-http-spy", "0.2.1"
|
25
25
|
s.add_development_dependency "coveralls"
|
26
|
-
s.add_dependency "
|
26
|
+
s.add_dependency "excon", "~> 0.33.0"
|
27
27
|
s.add_dependency "json", ">= 1.7.7"
|
28
28
|
s.add_dependency "os", ">= 0.9.6"
|
29
29
|
s.add_dependency "rubyzip", ">= 1.0.0"
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Neography::Rest do
|
4
|
+
before(:each) do
|
5
|
+
@neo = Neography::Rest.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "no streaming" do
|
9
|
+
|
10
|
+
it "can send a 1000 item batch" do
|
11
|
+
commands = []
|
12
|
+
1000.times do |x|
|
13
|
+
commands << [:create_node, {"name" => "Max " + x.to_s}]
|
14
|
+
end
|
15
|
+
batch_result = @neo.batch_no_streaming *commands
|
16
|
+
batch_result.first["body"]["data"]["name"].should == "Max 0"
|
17
|
+
batch_result.last["body"]["data"]["name"].should == "Max 999"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "can send a 5000 item batch" do
|
21
|
+
commands = []
|
22
|
+
5000.times do |x|
|
23
|
+
commands << [:get_node, 0]
|
24
|
+
end
|
25
|
+
batch_result = @neo.batch_no_streaming *commands
|
26
|
+
batch_result.first["body"]["self"].split('/').last.should == "0"
|
27
|
+
batch_result.last["body"]["self"].split('/').last.should == "0"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "can send a 20000 item batch" do
|
31
|
+
commands = []
|
32
|
+
20000.times do |x|
|
33
|
+
commands << [:create_node, {"name" => "Max " + x.to_s}]
|
34
|
+
end
|
35
|
+
batch_result = @neo.batch_no_streaming *commands
|
36
|
+
batch_result.first["body"]["data"]["name"].should == "Max 0"
|
37
|
+
batch_result.last["body"]["data"]["name"].should == "Max 19999"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -566,4 +566,18 @@ describe Neography::Rest do
|
|
566
566
|
end
|
567
567
|
end
|
568
568
|
|
569
|
+
describe "batch unknown option" do
|
570
|
+
it "should raise Neography::UnknownBatchOptionException when bad option is passed in batch" do
|
571
|
+
batch_commands = []
|
572
|
+
|
573
|
+
batch_commands << [ :bad_option, "start person_n=node:person(ssn = '000-00-0002')
|
574
|
+
set bar1 = {foo}"]
|
575
|
+
|
576
|
+
expect {
|
577
|
+
batch_result = @neo.batch *batch_commands
|
578
|
+
}.to raise_exception Neography::UnknownBatchOptionException
|
579
|
+
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
569
583
|
end
|
@@ -15,7 +15,7 @@ describe Neography::Rest do
|
|
15
15
|
batch_result = @neo.batch *commands
|
16
16
|
batch_result.first["body"]["data"]["name"].should == "Max 0"
|
17
17
|
batch_result.last["body"]["data"]["name"].should == "Max 999"
|
18
|
-
end
|
18
|
+
end
|
19
19
|
|
20
20
|
it "can send a 5000 item batch" do
|
21
21
|
commands = []
|
@@ -25,8 +25,27 @@ describe Neography::Rest do
|
|
25
25
|
batch_result = @neo.batch *commands
|
26
26
|
batch_result.first["body"]["self"].split('/').last.should == "0"
|
27
27
|
batch_result.last["body"]["self"].split('/').last.should == "0"
|
28
|
-
end
|
28
|
+
end
|
29
29
|
|
30
|
-
|
30
|
+
it "can send a 7000 get item batch" do
|
31
|
+
commands = []
|
32
|
+
7000.times do |x|
|
33
|
+
commands << [:get_node, 0]
|
34
|
+
end
|
35
|
+
batch_result = @neo.batch *commands
|
36
|
+
batch_result.first["body"]["self"].split('/').last.should == "0"
|
37
|
+
batch_result.last["body"]["self"].split('/').last.should == "0"
|
38
|
+
end
|
31
39
|
|
40
|
+
it "can send a 5000 create item batch" do
|
41
|
+
commands = []
|
42
|
+
5000.times do |x|
|
43
|
+
commands << [:create_node, {"name" => "Max " + x.to_s}]
|
44
|
+
end
|
45
|
+
batch_result = @neo.batch *commands
|
46
|
+
batch_result.first["body"]["data"]["name"].should == "Max 0"
|
47
|
+
batch_result.last["body"]["data"]["name"].should == "Max 4999"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
32
51
|
end
|
@@ -420,7 +420,10 @@ describe Neography::Rest do
|
|
420
420
|
it "can query a node from an automatic index" do
|
421
421
|
new_node = @neo.create_node("name" => "Max")
|
422
422
|
existing_nodes = @neo.find_node_auto_index("name:Max")
|
423
|
-
existing_nodes.collect{|n| n["self"]}.include?(new_node["self"]).should be_true
|
423
|
+
existing_nodes.collect{|n| n["self"]}.include?(new_node["self"]).should be_true
|
424
|
+
# check that more complex queries are correctly handled
|
425
|
+
existing_nodes = @neo.find_node_auto_index("name:Max OR name:Max")
|
426
|
+
existing_nodes.collect{|n| n["self"]}.include?(new_node["self"]).should be_true
|
424
427
|
end
|
425
428
|
|
426
429
|
it "can get a relationship from an automatic index" do
|
data/spec/spec_helper.rb
CHANGED
@@ -34,7 +34,7 @@ def error_response(attributes)
|
|
34
34
|
|
35
35
|
double(
|
36
36
|
http_header: http_header,
|
37
|
-
|
37
|
+
status: attributes[:code],
|
38
38
|
body: {
|
39
39
|
message: attributes[:message],
|
40
40
|
exception: attributes[:exception],
|
@@ -42,4 +42,3 @@ def error_response(attributes)
|
|
42
42
|
}.reject { |k,v| v.nil? }.to_json
|
43
43
|
)
|
44
44
|
end
|
45
|
-
|
data/spec/unit/config_spec.rb
CHANGED
@@ -7,44 +7,49 @@ module Neography
|
|
7
7
|
|
8
8
|
context "defaults" do
|
9
9
|
|
10
|
-
its(:protocol)
|
11
|
-
its(:server)
|
12
|
-
its(:port)
|
13
|
-
its(:directory)
|
14
|
-
its(:cypher_path)
|
15
|
-
its(:gremlin_path)
|
16
|
-
its(:log_file)
|
17
|
-
its(:log_enabled)
|
18
|
-
its(:logger)
|
19
|
-
its(:slow_log_threshold)
|
20
|
-
its(:max_threads)
|
21
|
-
its(:authentication)
|
22
|
-
its(:username)
|
23
|
-
its(:password)
|
24
|
-
its(:parser)
|
25
|
-
its(:max_execution_time)
|
26
|
-
its(:proxy)
|
10
|
+
its(:protocol) { should == 'http://' }
|
11
|
+
its(:server) { should == 'localhost' }
|
12
|
+
its(:port) { should == 7474 }
|
13
|
+
its(:directory) { should == '' }
|
14
|
+
its(:cypher_path) { should == '/cypher' }
|
15
|
+
its(:gremlin_path) { should == '/ext/GremlinPlugin/graphdb/execute_script' }
|
16
|
+
its(:log_file) { should == 'neography.log' }
|
17
|
+
its(:log_enabled) { should == false }
|
18
|
+
its(:logger) { should == nil }
|
19
|
+
its(:slow_log_threshold) { should == 0 }
|
20
|
+
its(:max_threads) { should == 20 }
|
21
|
+
its(:authentication) { should == nil }
|
22
|
+
its(:username) { should == nil }
|
23
|
+
its(:password) { should == nil }
|
24
|
+
its(:parser) { should == MultiJsonParser}
|
25
|
+
its(:max_execution_time) { should == 6000 }
|
26
|
+
its(:proxy) { should == nil }
|
27
|
+
its(:http_send_timeout) { should == 1200 }
|
28
|
+
its(:http_receive_timeout) { should == 1200 }
|
27
29
|
|
28
30
|
|
29
31
|
it "has a hash representation" do
|
30
32
|
expected_hash = {
|
31
|
-
:protocol
|
32
|
-
:server
|
33
|
-
:port
|
34
|
-
:directory
|
35
|
-
:cypher_path
|
36
|
-
:gremlin_path
|
37
|
-
:log_file
|
38
|
-
:log_enabled
|
39
|
-
:logger
|
40
|
-
:slow_log_threshold
|
41
|
-
:max_threads
|
42
|
-
:authentication
|
43
|
-
:username
|
44
|
-
:password
|
45
|
-
:parser
|
46
|
-
:max_execution_time
|
47
|
-
:proxy
|
33
|
+
:protocol => 'http://',
|
34
|
+
:server => 'localhost',
|
35
|
+
:port => 7474,
|
36
|
+
:directory => '',
|
37
|
+
:cypher_path => '/cypher',
|
38
|
+
:gremlin_path => '/ext/GremlinPlugin/graphdb/execute_script',
|
39
|
+
:log_file => 'neography.log',
|
40
|
+
:log_enabled => false,
|
41
|
+
:logger => nil,
|
42
|
+
:slow_log_threshold => 0,
|
43
|
+
:max_threads => 20,
|
44
|
+
:authentication => nil,
|
45
|
+
:username => nil,
|
46
|
+
:password => nil,
|
47
|
+
:parser => MultiJsonParser,
|
48
|
+
:max_execution_time => 6000,
|
49
|
+
:proxy => nil,
|
50
|
+
:http_send_timeout => 1200,
|
51
|
+
:http_receive_timeout => 1200
|
52
|
+
|
48
53
|
}
|
49
54
|
config.to_hash.should == expected_hash
|
50
55
|
end
|
@@ -59,8 +59,30 @@ module Neography
|
|
59
59
|
}
|
60
60
|
}
|
61
61
|
end
|
62
|
+
|
63
|
+
context "httpclient" do
|
64
|
+
let(:httpclient) { double(:http_client) }
|
65
|
+
let(:options) do
|
66
|
+
{
|
67
|
+
:http_send_timeout => 120,
|
68
|
+
:http_receive_timeout => 100
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'configures send/receive timeout' do
|
73
|
+
Excon.should_receive(:new).with("http://localhost:7474",
|
74
|
+
:read_timeout => 100,
|
75
|
+
:write_timeout => 120,
|
76
|
+
:persistent=>true,
|
77
|
+
:user=>nil,
|
78
|
+
:password=>nil).and_return(httpclient)
|
79
|
+
connection
|
80
|
+
end
|
81
|
+
end
|
62
82
|
end
|
63
83
|
|
84
|
+
|
85
|
+
|
64
86
|
context "string option" do
|
65
87
|
let(:options) { "https://user:pass@somehost:8585/path" }
|
66
88
|
|
@@ -80,22 +102,22 @@ module Neography
|
|
80
102
|
context "requests" do
|
81
103
|
|
82
104
|
it "does a GET request" do
|
83
|
-
connection.client.should_receive(:
|
105
|
+
connection.client.should_receive(:request).with(:method => :get, :path => "/db/data/node/bar", :body => nil, :headers => nil) { double.as_null_object }
|
84
106
|
connection.get("/node/bar")
|
85
107
|
end
|
86
108
|
|
87
109
|
it "does a POST request" do
|
88
|
-
connection.client.should_receive(:
|
110
|
+
connection.client.should_receive(:request).with(:method => :post, :path => "/db/data/node/bar", :body => nil, :headers => nil) { double.as_null_object }
|
89
111
|
connection.post("/node/bar")
|
90
112
|
end
|
91
113
|
|
92
114
|
it "does a PUT request" do
|
93
|
-
connection.client.should_receive(:
|
115
|
+
connection.client.should_receive(:request).with(:method => :put, :path => "/db/data/node/bar", :body => nil, :headers => nil) { double.as_null_object }
|
94
116
|
connection.put("/node/bar")
|
95
117
|
end
|
96
118
|
|
97
119
|
it "does a DELETE request" do
|
98
|
-
connection.client.should_receive(:
|
120
|
+
connection.client.should_receive(:request).with(:method => :delete, :path => "/db/data/node/bar", :body => nil, :headers => nil) { double.as_null_object }
|
99
121
|
connection.delete("/node/bar")
|
100
122
|
end
|
101
123
|
|
@@ -114,19 +136,20 @@ module Neography
|
|
114
136
|
"foo",
|
115
137
|
"bar") { double.as_null_object }
|
116
138
|
|
117
|
-
connection.client.should_receive(:
|
118
|
-
"
|
119
|
-
) { double.as_null_object }
|
139
|
+
connection.client.should_receive(:request).with(
|
140
|
+
:method => :get, :path => "/db/data/node/bar", :body => nil, :headers => nil) { double.as_null_object }
|
120
141
|
|
121
142
|
connection.get("/node/bar")
|
122
143
|
end
|
123
144
|
end
|
124
145
|
|
125
146
|
it "adds the User-Agent to the headers" do
|
126
|
-
connection.client.should_receive(:
|
127
|
-
|
128
|
-
|
129
|
-
|
147
|
+
connection.client.should_receive(:request).with(
|
148
|
+
hash_including(
|
149
|
+
{:method => :get, :path => "/db/data/node/bar", :body => nil,
|
150
|
+
:headers => {"User-Agent" => "Neography/#{Neography::VERSION}", "X-Stream"=>true, "max-execution-time" => 6000}}
|
151
|
+
)
|
152
|
+
) { double.as_null_object }
|
130
153
|
|
131
154
|
connection.get("/node/bar", :headers => {})
|
132
155
|
end
|
@@ -135,7 +158,7 @@ module Neography
|
|
135
158
|
|
136
159
|
it "raises NodeNotFoundException" do
|
137
160
|
response = error_response(code: 404, message: "a message", exception: "NodeNotFoundException")
|
138
|
-
connection.client.stub(:
|
161
|
+
connection.client.stub(:request).and_return(response)
|
139
162
|
expect {
|
140
163
|
connection.get("/node/bar")
|
141
164
|
}.to raise_error NodeNotFoundException
|
@@ -143,7 +166,7 @@ module Neography
|
|
143
166
|
|
144
167
|
it "raises OperationFailureException" do
|
145
168
|
response = error_response(code: 409, message: "a message", exception: "OperationFailureException")
|
146
|
-
connection.client.stub(:
|
169
|
+
connection.client.stub(:request).and_return(response)
|
147
170
|
expect {
|
148
171
|
connection.get("/node/bar")
|
149
172
|
}.to raise_error OperationFailureException
|
@@ -151,7 +174,7 @@ module Neography
|
|
151
174
|
|
152
175
|
it "raises PropertyValueException" do
|
153
176
|
response = error_response(code: 400, message: "a message", exception: "PropertyValueException")
|
154
|
-
connection.client.stub(:
|
177
|
+
connection.client.stub(:request).and_return(response)
|
155
178
|
expect {
|
156
179
|
connection.get("/node/bar")
|
157
180
|
}.to raise_error PropertyValueException
|
@@ -159,7 +182,7 @@ module Neography
|
|
159
182
|
|
160
183
|
it "raises NoSuchPropertyException" do
|
161
184
|
response = error_response(code: 404, message: "a message", exception: "NoSuchPropertyException")
|
162
|
-
connection.client.stub(:
|
185
|
+
connection.client.stub(:request).and_return(response)
|
163
186
|
expect {
|
164
187
|
connection.get("/node/bar")
|
165
188
|
}.to raise_error NoSuchPropertyException
|
@@ -167,7 +190,7 @@ module Neography
|
|
167
190
|
|
168
191
|
it "raises RelationshipNotFoundException" do
|
169
192
|
response = error_response(code: 404, message: "a message", exception: "RelationshipNotFoundException")
|
170
|
-
connection.client.stub(:
|
193
|
+
connection.client.stub(:request).and_return(response)
|
171
194
|
expect {
|
172
195
|
connection.get("/node/bar")
|
173
196
|
}.to raise_error RelationshipNotFoundException
|
@@ -175,7 +198,7 @@ module Neography
|
|
175
198
|
|
176
199
|
it "raises BadInputException" do
|
177
200
|
response = error_response(code: 400, message: "a message", exception: "BadInputException")
|
178
|
-
connection.client.stub(:
|
201
|
+
connection.client.stub(:request).and_return(response)
|
179
202
|
expect {
|
180
203
|
connection.get("/node/bar")
|
181
204
|
}.to raise_error BadInputException
|
@@ -183,7 +206,7 @@ module Neography
|
|
183
206
|
|
184
207
|
it "raises UnauthorizedError" do
|
185
208
|
response = error_response(code: 401)
|
186
|
-
connection.client.stub(:
|
209
|
+
connection.client.stub(:request).and_return(response)
|
187
210
|
expect {
|
188
211
|
connection.get("/node/bar")
|
189
212
|
}.to raise_error UnauthorizedError
|
@@ -191,7 +214,7 @@ module Neography
|
|
191
214
|
|
192
215
|
it "raises NeographyError in all other cases" do
|
193
216
|
response = error_response(code: 418, message: "I'm a teapot.")
|
194
|
-
connection.client.stub(:
|
217
|
+
connection.client.stub(:request).and_return(response)
|
195
218
|
expect {
|
196
219
|
connection.get("/node/bar")
|
197
220
|
}.to raise_error NeographyError
|
@@ -199,7 +222,7 @@ module Neography
|
|
199
222
|
|
200
223
|
it "raises BadInputException" do
|
201
224
|
response = error_response(code: 500, message: "a message", exception: "JsonParseException")
|
202
|
-
connection.client.stub(:
|
225
|
+
connection.client.stub(:request).and_return(response)
|
203
226
|
expect {
|
204
227
|
connection.get("/node/bar")
|
205
228
|
}.to raise_error NeographyError
|
@@ -208,52 +231,54 @@ module Neography
|
|
208
231
|
end
|
209
232
|
|
210
233
|
context "query logging" do
|
211
|
-
before do
|
212
|
-
@logger = Logger.new(nil)
|
213
|
-
connection.logger = @logger
|
214
|
-
connection.log_enabled = true
|
215
|
-
end
|
216
234
|
|
217
|
-
|
235
|
+
subject(:connection) do
|
218
236
|
|
219
|
-
|
237
|
+
Connection.new({
|
238
|
+
:logger => Logger.new(nil),
|
239
|
+
:log_enabled => true
|
240
|
+
})
|
241
|
+
|
242
|
+
let(:expected_response) {"expected_response"}
|
220
243
|
|
221
|
-
|
222
|
-
connection.should_receive(:log).with("/db/data/node/bar", request_body).once
|
223
|
-
connection.get("/node/bar", {body: request_body})
|
224
|
-
end
|
244
|
+
let(:request_body) { {key1: :val1} }
|
225
245
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
246
|
+
it "should log query" do
|
247
|
+
connection.should_receive(:log).with("/db/data/node/bar", request_body).once
|
248
|
+
connection.get("/node/bar", {body: request_body})
|
249
|
+
end
|
230
250
|
|
231
|
-
|
232
|
-
before do
|
251
|
+
it "should return original response" do
|
233
252
|
connection.stub(:evaluate_response).and_return expected_response
|
253
|
+
connection.get("/node/bar").should eq expected_response
|
234
254
|
end
|
235
255
|
|
236
|
-
|
237
|
-
|
238
|
-
|
256
|
+
describe "slow_log_threshold" do
|
257
|
+
before do
|
258
|
+
connection.stub(:evaluate_response).and_return expected_response
|
239
259
|
end
|
240
|
-
end
|
241
260
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
261
|
+
context "default value" do
|
262
|
+
it "should have output" do
|
263
|
+
@logger.should_receive(:info).once
|
264
|
+
end
|
246
265
|
end
|
247
|
-
end
|
248
266
|
|
249
|
-
|
250
|
-
|
267
|
+
context "high value" do
|
268
|
+
before { connection.slow_log_threshold = 100_000 }
|
269
|
+
it "should not have output" do
|
270
|
+
@logger.should_not_receive(:info)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
after do
|
275
|
+
connection.get("/node/bar", {body: request_body})
|
276
|
+
end
|
251
277
|
end
|
252
278
|
end
|
253
|
-
|
254
279
|
end
|
255
280
|
end
|
256
281
|
end
|
257
282
|
end
|
258
283
|
|
259
|
-
class Foo; end
|
284
|
+
class Foo; end
|
@@ -24,6 +24,10 @@ module Neography
|
|
24
24
|
it "finds by query if no value passed to #find_or_query" do
|
25
25
|
subject.connection.should_receive(:get).with("/index/auto/node/?query=some_query")
|
26
26
|
subject.find_node_auto_index("some_query")
|
27
|
+
|
28
|
+
query = "some_query AND another_one"
|
29
|
+
subject.connection.should_receive(:get).with("/index/auto/node/?query=#{URI.encode(query)}")
|
30
|
+
subject.find_node_auto_index(query)
|
27
31
|
end
|
28
32
|
|
29
33
|
it "finds by key and value" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: neography
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max De Marzi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -53,19 +53,19 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: excon
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: 0.33.0
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: 0.33.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: json
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -217,6 +217,7 @@ files:
|
|
217
217
|
- spec/integration/parsing_spec.rb
|
218
218
|
- spec/integration/performance_spec.rb
|
219
219
|
- spec/integration/relationship_spec.rb
|
220
|
+
- spec/integration/rest_batch_no_streaming_spec.rb
|
220
221
|
- spec/integration/rest_batch_spec.rb
|
221
222
|
- spec/integration/rest_batch_streaming_spec.rb
|
222
223
|
- spec/integration/rest_bulk_spec.rb
|
@@ -303,6 +304,7 @@ test_files:
|
|
303
304
|
- spec/integration/parsing_spec.rb
|
304
305
|
- spec/integration/performance_spec.rb
|
305
306
|
- spec/integration/relationship_spec.rb
|
307
|
+
- spec/integration/rest_batch_no_streaming_spec.rb
|
306
308
|
- spec/integration/rest_batch_spec.rb
|
307
309
|
- spec/integration/rest_batch_streaming_spec.rb
|
308
310
|
- spec/integration/rest_bulk_spec.rb
|