neography-calamitates 1.2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. data/.gitignore +15 -0
  2. data/.project +12 -0
  3. data/.travis.yml +4 -0
  4. data/CONTRIBUTORS +18 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +19 -0
  7. data/README.md +261 -0
  8. data/Rakefile +14 -0
  9. data/examples/facebook.rb +40 -0
  10. data/examples/facebook_v2.rb +25 -0
  11. data/examples/greatest.rb +43 -0
  12. data/examples/linkedin.rb +39 -0
  13. data/examples/linkedin_v2.rb +22 -0
  14. data/examples/traversal_example1.rb +65 -0
  15. data/examples/traversal_example2.rb +54 -0
  16. data/lib/neography.rb +45 -0
  17. data/lib/neography/config.rb +52 -0
  18. data/lib/neography/connection.rb +203 -0
  19. data/lib/neography/equal.rb +21 -0
  20. data/lib/neography/errors.rb +45 -0
  21. data/lib/neography/index.rb +52 -0
  22. data/lib/neography/multi_json_parser.rb +28 -0
  23. data/lib/neography/neography.rb +10 -0
  24. data/lib/neography/node.rb +53 -0
  25. data/lib/neography/node_path.rb +29 -0
  26. data/lib/neography/node_relationship.rb +37 -0
  27. data/lib/neography/node_traverser.rb +146 -0
  28. data/lib/neography/path_traverser.rb +100 -0
  29. data/lib/neography/property.rb +61 -0
  30. data/lib/neography/property_container.rb +29 -0
  31. data/lib/neography/railtie.rb +19 -0
  32. data/lib/neography/relationship.rb +70 -0
  33. data/lib/neography/relationship_traverser.rb +80 -0
  34. data/lib/neography/rest.rb +470 -0
  35. data/lib/neography/rest/auto_indexes.rb +64 -0
  36. data/lib/neography/rest/batch.rb +277 -0
  37. data/lib/neography/rest/clean.rb +19 -0
  38. data/lib/neography/rest/cypher.rb +33 -0
  39. data/lib/neography/rest/extensions.rb +25 -0
  40. data/lib/neography/rest/gremlin.rb +24 -0
  41. data/lib/neography/rest/helpers.rb +38 -0
  42. data/lib/neography/rest/indexes.rb +100 -0
  43. data/lib/neography/rest/node_auto_indexes.rb +14 -0
  44. data/lib/neography/rest/node_indexes.rb +50 -0
  45. data/lib/neography/rest/node_labels.rb +60 -0
  46. data/lib/neography/rest/node_paths.rb +57 -0
  47. data/lib/neography/rest/node_properties.rb +11 -0
  48. data/lib/neography/rest/node_relationships.rb +42 -0
  49. data/lib/neography/rest/node_traversal.rb +81 -0
  50. data/lib/neography/rest/nodes.rb +102 -0
  51. data/lib/neography/rest/other_node_relationships.rb +48 -0
  52. data/lib/neography/rest/paths.rb +36 -0
  53. data/lib/neography/rest/properties.rb +56 -0
  54. data/lib/neography/rest/relationship_auto_indexes.rb +14 -0
  55. data/lib/neography/rest/relationship_indexes.rb +35 -0
  56. data/lib/neography/rest/relationship_properties.rb +11 -0
  57. data/lib/neography/rest/relationship_types.rb +18 -0
  58. data/lib/neography/rest/relationships.rb +23 -0
  59. data/lib/neography/rest/schema_indexes.rb +34 -0
  60. data/lib/neography/rest/transactions.rb +102 -0
  61. data/lib/neography/tasks.rb +158 -0
  62. data/lib/neography/version.rb +3 -0
  63. data/neography.gemspec +32 -0
  64. data/spec/integration/authorization_spec.rb +48 -0
  65. data/spec/integration/index_spec.rb +70 -0
  66. data/spec/integration/neography_spec.rb +10 -0
  67. data/spec/integration/node_encoding_spec.rb +71 -0
  68. data/spec/integration/node_path_spec.rb +222 -0
  69. data/spec/integration/node_relationship_spec.rb +381 -0
  70. data/spec/integration/node_spec.rb +251 -0
  71. data/spec/integration/parsing_spec.rb +13 -0
  72. data/spec/integration/performance_spec.rb +17 -0
  73. data/spec/integration/relationship_spec.rb +37 -0
  74. data/spec/integration/rest_batch_spec.rb +512 -0
  75. data/spec/integration/rest_batch_streaming_spec.rb +32 -0
  76. data/spec/integration/rest_bulk_spec.rb +106 -0
  77. data/spec/integration/rest_experimental_spec.rb +22 -0
  78. data/spec/integration/rest_gremlin_fail_spec.rb +46 -0
  79. data/spec/integration/rest_header_spec.rb +14 -0
  80. data/spec/integration/rest_index_spec.rb +468 -0
  81. data/spec/integration/rest_labels_spec.rb +128 -0
  82. data/spec/integration/rest_node_spec.rb +274 -0
  83. data/spec/integration/rest_other_node_relationship_spec.rb +137 -0
  84. data/spec/integration/rest_path_spec.rb +231 -0
  85. data/spec/integration/rest_plugin_spec.rb +177 -0
  86. data/spec/integration/rest_relationship_spec.rb +354 -0
  87. data/spec/integration/rest_relationship_types_spec.rb +18 -0
  88. data/spec/integration/rest_schema_index_spec.rb +32 -0
  89. data/spec/integration/rest_transaction_spec.rb +166 -0
  90. data/spec/integration/rest_traverse_spec.rb +149 -0
  91. data/spec/matchers.rb +33 -0
  92. data/spec/neography_spec.rb +23 -0
  93. data/spec/spec_helper.rb +45 -0
  94. data/spec/unit/config_spec.rb +46 -0
  95. data/spec/unit/connection_spec.rb +211 -0
  96. data/spec/unit/node_spec.rb +100 -0
  97. data/spec/unit/properties_spec.rb +140 -0
  98. data/spec/unit/relationship_spec.rb +118 -0
  99. data/spec/unit/rest/batch_spec.rb +243 -0
  100. data/spec/unit/rest/clean_spec.rb +17 -0
  101. data/spec/unit/rest/cypher_spec.rb +21 -0
  102. data/spec/unit/rest/extensions_spec.rb +29 -0
  103. data/spec/unit/rest/gremlin_spec.rb +26 -0
  104. data/spec/unit/rest/labels_spec.rb +73 -0
  105. data/spec/unit/rest/node_auto_indexes_spec.rb +67 -0
  106. data/spec/unit/rest/node_indexes_spec.rb +141 -0
  107. data/spec/unit/rest/node_paths_spec.rb +80 -0
  108. data/spec/unit/rest/node_properties_spec.rb +80 -0
  109. data/spec/unit/rest/node_relationships_spec.rb +78 -0
  110. data/spec/unit/rest/node_traversal_spec.rb +128 -0
  111. data/spec/unit/rest/nodes_spec.rb +188 -0
  112. data/spec/unit/rest/paths_spec.rb +69 -0
  113. data/spec/unit/rest/relationship_auto_indexes_spec.rb +67 -0
  114. data/spec/unit/rest/relationship_indexes_spec.rb +132 -0
  115. data/spec/unit/rest/relationship_properties_spec.rb +80 -0
  116. data/spec/unit/rest/relationship_types_spec.rb +16 -0
  117. data/spec/unit/rest/relationships_spec.rb +22 -0
  118. data/spec/unit/rest/schema_index_spec.rb +31 -0
  119. data/spec/unit/rest/transactions_spec.rb +44 -0
  120. metadata +372 -0
@@ -0,0 +1,39 @@
1
+ require 'rubygems'
2
+ require 'neography'
3
+
4
+ @neo = Neography::Rest.new
5
+
6
+ def create_person(name)
7
+ @neo.create_node("name" => name)
8
+ end
9
+
10
+ def make_mutual_friends(node1, node2)
11
+ @neo.create_relationship("friends", node1, node2)
12
+ @neo.create_relationship("friends", node2, node1)
13
+ end
14
+
15
+ def degrees_of_separation(start_node, destination_node)
16
+ paths = @neo.get_paths(start_node, destination_node, {"type"=> "friends", "direction" => "in"}, depth=4, algorithm="allSimplePaths")
17
+ paths.each do |p|
18
+ p["names"] = p["nodes"].collect {|node| @neo.get_node_properties(node, "name")["name"] }
19
+ end
20
+
21
+ end
22
+
23
+ johnathan = create_person('Johnathan')
24
+ mark = create_person('Mark')
25
+ phill = create_person('Phill')
26
+ mary = create_person('Mary')
27
+
28
+ make_mutual_friends(johnathan, mark)
29
+ make_mutual_friends(mark, phill)
30
+ make_mutual_friends(phill, mary)
31
+ make_mutual_friends(mark, mary)
32
+
33
+ degrees_of_separation(johnathan, mary).each do |path|
34
+ puts path["names"].join(' => friends => ')
35
+ end
36
+
37
+ # RESULT
38
+ # Johnathan => friends => Mark => friends => Phill => friends => Mary
39
+ # Johnathan => friends => Mark => friends => Mary
@@ -0,0 +1,22 @@
1
+ require 'rubygems'
2
+ require 'neography'
3
+
4
+ @neo = Neography::Rest.new
5
+
6
+ johnathan = Neography::Node.create("name" =>'Johnathan')
7
+ mark = Neography::Node.create("name" =>'Mark')
8
+ phill = Neography::Node.create("name" =>'Phill')
9
+ mary = Neography::Node.create("name" =>'Mary')
10
+
11
+ johnathan.both(:friends) << mark
12
+ mark.both(:friends) << phill
13
+ phill.both(:friends) << mary
14
+ mark.both(:friends) << mary
15
+
16
+ johnathan.all_simple_paths_to(mary).incoming(:friends).depth(4).nodes.each do |node|
17
+ puts node.map{|n| n.name }.join(' => friends => ')
18
+ end
19
+
20
+ # RESULT
21
+ # Johnathan => friends => Mark => friends => Phill => friends => Mary
22
+ # Johnathan => friends => Mark => friends => Mary
@@ -0,0 +1,65 @@
1
+ require 'rubygems'
2
+ require 'neography'
3
+
4
+ @neo = Neography::Rest.new
5
+
6
+ def create_node(level, type)
7
+ @neo.create_node("NODE_LEVEL" => level, "TYPE" => type)
8
+ end
9
+
10
+ def create_other_node(type)
11
+ @neo.create_node("TYPE" => type)
12
+ end
13
+
14
+
15
+ def get_nodes_by_level(level, node)
16
+ starting_id = node["self"].split('/').last
17
+
18
+ @neo.traverse(node,"nodes", {"order" => "breadth first",
19
+ "uniqueness" => "node global",
20
+ "relationships" => {"type"=> "linked", "direction" => "out"},
21
+ "prune evaluator" => {
22
+ "language" => "javascript",
23
+ "body" => "position.startNode().hasProperty('NODE_LEVEL')
24
+ && position.startNode().getProperty('NODE_LEVEL')==5
25
+ && position.startNode().getId()!=#{starting_id};"},
26
+ "return filter" => {
27
+ "language" => "javascript",
28
+ "body" => "position.endNode().hasProperty('NODE_LEVEL') && position.endNode().getProperty('NODE_LEVEL')==5;"}})
29
+ end
30
+
31
+ node1 = create_node(5, "N")
32
+ node2 = create_node(5, "N")
33
+ node3 = create_node(5, "N")
34
+ node4 = create_node(5, "N")
35
+ node5 = create_node(5, "N")
36
+ node6 = create_node(5, "N")
37
+ node7 = create_node(5, "N")
38
+
39
+ node8 = create_other_node("Y")
40
+ node9 = create_other_node("Y")
41
+ node10 = create_other_node("Y")
42
+
43
+ node11 = create_node(6, "N")
44
+ node12 = create_node(7, "N")
45
+ node13 = create_node(8, "N")
46
+
47
+
48
+ @neo.create_relationship("linked", node1, node2)
49
+ @neo.create_relationship("linked", node2, node3)
50
+ @neo.create_relationship("linked", node3, node4)
51
+ @neo.create_relationship("linked", node4, node5)
52
+ @neo.create_relationship("linked", node5, node6)
53
+ @neo.create_relationship("linked", node6, node7)
54
+
55
+ @neo.create_relationship("linked", node2, node8)
56
+ @neo.create_relationship("linked", node3, node9)
57
+ @neo.create_relationship("linked", node4, node10)
58
+
59
+ @neo.create_relationship("linked", node5, node11)
60
+ @neo.create_relationship("linked", node6, node12)
61
+ @neo.create_relationship("linked", node7, node13)
62
+
63
+ puts "The node levels returned are #{get_nodes_by_level(5, node1).map{|n| n["data"]["NODE_LEVEL"]}.join(', ')}"
64
+
65
+ # The node levels returned are 5, 5, 5, 5, 5, 5, 5
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'neography'
3
+
4
+ @neo = Neography::Rest.new
5
+
6
+ def create_node(name, mysql_id)
7
+ @neo.create_node("name" => name, "mysql_id" => mysql_id)
8
+ end
9
+
10
+ def attended(student, school, degree, graduated)
11
+ @neo.create_relationship("attended", student, school, {"degree" => degree, "graduated" => graduated})
12
+ end
13
+
14
+
15
+ def graduated_with_me(student)
16
+ student = student["self"].split('/').last
17
+ student_attended = @neo.get_node_relationships(student)[0]
18
+ graduated = student_attended["data"]["graduated"]
19
+ school = student_attended["end"].split('/').last
20
+
21
+ @neo.traverse(school,"nodes", {"order" => "breadth first",
22
+ "uniqueness" => "node global",
23
+ "relationships" => {"type"=> "attended", "direction" => "in"},
24
+ "return filter" => {
25
+ "language" => "javascript",
26
+ "body" => "position.length() == 1
27
+ && position.endNode().getId() != #{student}
28
+ && position.lastRelationship().getProperty(\"graduated\") == #{graduated};"}})
29
+ end
30
+
31
+ charlie = create_node("Charlie", 1)
32
+ max = create_node("Max", 2)
33
+ peter = create_node("Peter", 3)
34
+ carol = create_node("Carol", 3)
35
+ tom = create_node("Tom", 4)
36
+ jerry = create_node("Jerry", 5)
37
+ larry = create_node("Larry", 6)
38
+
39
+ yale = create_node("Yale", 7)
40
+ harvard = create_node("Harvard", 8)
41
+ rutgers = create_node("Rutgers", 9)
42
+
43
+ attended(charlie,yale,"engineering", 2010)
44
+ attended(max,yale,"mathematics", 2005)
45
+ attended(peter,yale,"biology", 2010)
46
+ attended(carol,yale,"engineering", 2010)
47
+ attended(tom,harvard,"biology", 2008)
48
+ attended(jerry,rutgers,"physics", 2007)
49
+ attended(larry,rutgers,"mathematics", 2010)
50
+
51
+
52
+ puts "Charlie graduated with #{graduated_with_me(charlie).map{|n| n["data"]["name"]}.join(', ')}"
53
+
54
+ # The node levels returned are Peter, Carol
@@ -0,0 +1,45 @@
1
+ require 'cgi'
2
+ require 'httpclient'
3
+ require 'json'
4
+ require 'multi_json'
5
+ require 'logger'
6
+ require 'ostruct'
7
+ require 'os'
8
+ require 'zip/filesystem'
9
+
10
+ require 'neography/multi_json_parser'
11
+
12
+ require 'neography/version'
13
+
14
+ require 'neography/config'
15
+
16
+ require 'neography/rest'
17
+
18
+ require 'neography/neography'
19
+
20
+ require 'neography/property_container'
21
+ require 'neography/property'
22
+ require 'neography/node_relationship'
23
+ require 'neography/node_path'
24
+ require 'neography/relationship_traverser'
25
+ require 'neography/node_traverser'
26
+ require 'neography/path_traverser'
27
+ require 'neography/equal'
28
+ require 'neography/index'
29
+
30
+ require 'neography/node'
31
+ require 'neography/relationship'
32
+
33
+ require 'neography/railtie' if defined? Rails::Railtie
34
+
35
+ module Neography
36
+
37
+ def self.configure
38
+ yield configuration
39
+ end
40
+
41
+ def self.configuration
42
+ @configuration ||= Config.new
43
+ end
44
+
45
+ end
@@ -0,0 +1,52 @@
1
+ module Neography
2
+ class Config
3
+
4
+ attr_accessor :protocol, :server, :port, :directory,
5
+ :cypher_path, :gremlin_path,
6
+ :log_file, :log_enabled,
7
+ :max_threads,
8
+ :authentication, :username, :password,
9
+ :parser
10
+
11
+ def initialize
12
+ set_defaults
13
+ end
14
+
15
+ def to_hash
16
+ {
17
+ :protocol => @protocol,
18
+ :server => @server,
19
+ :port => @port,
20
+ :directory => @directory,
21
+ :cypher_path => @cypher_path,
22
+ :gremlin_path => @gremlin_path,
23
+ :log_file => @log_file,
24
+ :log_enabled => @log_enabled,
25
+ :max_threads => @max_threads,
26
+ :authentication => @authentication,
27
+ :username => @username,
28
+ :password => @password,
29
+ :parser => @parser
30
+ }
31
+ end
32
+
33
+ private
34
+
35
+ def set_defaults
36
+ @protocol = "http://"
37
+ @server = "localhost"
38
+ @port = 7474
39
+ @directory = ""
40
+ @cypher_path = "/cypher"
41
+ @gremlin_path = "/ext/GremlinPlugin/graphdb/execute_script"
42
+ @log_file = "neography.log"
43
+ @log_enabled = false
44
+ @max_threads = 20
45
+ @authentication = nil
46
+ @username = nil
47
+ @password = nil
48
+ @parser = MultiJsonParser
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,203 @@
1
+ module Neography
2
+ module WasCreated
3
+ end
4
+ class Connection
5
+ USER_AGENT = "Neography/#{Neography::VERSION}"
6
+ ACTIONS = ["get", "post", "put", "delete"]
7
+
8
+ attr_accessor :protocol, :server, :port, :directory,
9
+ :cypher_path, :gremlin_path,
10
+ :log_file, :log_enabled, :logger,
11
+ :max_threads,
12
+ :authentication, :username, :password,
13
+ :parser, :client
14
+
15
+ def initialize(options = ENV['NEO4J_URL'] || {})
16
+ config = merge_configuration(options)
17
+ save_local_configuration(config)
18
+ @client = HTTPClient.new
19
+ @client.send_timeout = 1200 # 10 minutes
20
+ @client.receive_timeout = 1200
21
+ end
22
+
23
+ def configure(protocol, server, port, directory)
24
+ @protocol = protocol
25
+ @server = server
26
+ @port = port
27
+ @directory = directory
28
+ end
29
+
30
+ def configuration
31
+ @configuration ||= "#{@protocol}#{@server}:#{@port}#{@directory}/db/data"
32
+ end
33
+
34
+ def merge_options(options)
35
+ merged_options = options.merge!(@authentication)
36
+ merged_options[:headers].merge!(@user_agent) if merged_options[:headers]
37
+ merged_options[:headers].merge!('X-Stream' => true) if merged_options[:headers]
38
+ merged_options
39
+ end
40
+
41
+ ACTIONS.each do |action|
42
+ define_method(action) do |path, options = {}|
43
+ authenticate(configuration + path)
44
+ evaluate_response(@client.send(action.to_sym, configuration + path, merge_options(options)[:body], merge_options(options)[:headers]))
45
+ end
46
+ end
47
+
48
+ def authenticate(path)
49
+ @client.set_auth(path,
50
+ @authentication[@authentication.keys.first][:username],
51
+ @authentication[@authentication.keys.first][:password]) unless @authentication.empty?
52
+ end
53
+
54
+ private
55
+
56
+ def merge_configuration(options)
57
+ options = parse_string_options(options) unless options.is_a? Hash
58
+ config = Neography.configuration.to_hash
59
+ config.merge(options)
60
+ end
61
+
62
+ def save_local_configuration(config)
63
+ @protocol = config[:protocol]
64
+ @server = config[:server]
65
+ @port = config[:port]
66
+ @directory = config[:directory]
67
+ @cypher_path = config[:cypher_path]
68
+ @gremlin_path = config[:gremlin_path]
69
+ @log_file = config[:log_file]
70
+ @log_enabled = config[:log_enabled]
71
+ @max_threads = config[:max_threads]
72
+ @parser = config[:parser]
73
+
74
+ @user_agent = { "User-Agent" => USER_AGENT }
75
+
76
+ @authentication = {}
77
+ if config[:authentication]
78
+ @authentication = {
79
+ "#{config[:authentication]}_auth".to_sym => {
80
+ :username => config[:username],
81
+ :password => config[:password]
82
+ }
83
+ }
84
+ end
85
+
86
+ if @log_enabled
87
+ @logger = Logger.new(@log_file)
88
+ end
89
+ end
90
+
91
+ def evaluate_chunk_response(response, result)
92
+ code = response.code
93
+ return_result(code, result)
94
+ end
95
+
96
+ def evaluate_response(response)
97
+ if response.http_header.request_uri.request_uri == "/db/data/batch"
98
+ code, body, parsed = handle_batch(response)
99
+ else
100
+ code = response.code
101
+ body = response.body.force_encoding("UTF-8")
102
+ parsed = false
103
+ end
104
+ return_result(code, body, parsed)
105
+ end
106
+
107
+ def handle_batch(response)
108
+ code = 200
109
+ body = @parser.json(response.body.force_encoding("UTF-8"))
110
+ body.each do |result|
111
+ if result["status"] >= 400
112
+ code = result["status"]
113
+ break
114
+ end
115
+ end
116
+ return code, body, true
117
+ end
118
+
119
+ def return_result(code, body, parsed)
120
+ case code
121
+ when 200
122
+ @logger.debug "OK, created #{body}" if @log_enabled
123
+ parsed ? body : @parser.json(body)
124
+ when 201
125
+ @logger.debug "OK, created #{body}" if @log_enabled
126
+ r = parsed ? body : @parser.json(body)
127
+ r.extend(WasCreated)
128
+ r
129
+ when 204
130
+ @logger.debug "OK, no content returned" if @log_enabled
131
+ nil
132
+ when 400..500
133
+ handle_4xx_500_response(code, body)
134
+ nil
135
+ end
136
+ end
137
+
138
+ def handle_4xx_500_response(code, body)
139
+ if body.nil? or body == ""
140
+ parsed_body = {"message" => "No error message returned from server.",
141
+ "stacktrace" => "No stacktrace returned from server." }
142
+ elsif body.is_a? Hash
143
+ parsed_body = body
144
+ elsif body.is_a? Array
145
+ body.each do |result|
146
+ if result["status"] >= 400
147
+ parsed_body = result["body"] || result
148
+ break
149
+ end
150
+ end
151
+ else
152
+ parsed_body = @parser.json(body)
153
+ end
154
+
155
+ message = parsed_body["message"]
156
+ stacktrace = parsed_body["stacktrace"]
157
+
158
+ @logger.error "#{code} error: #{body}" if @log_enabled
159
+ raise_errors(code, parsed_body["exception"], message, stacktrace)
160
+ end
161
+
162
+ def raise_errors(code, exception, message, stacktrace)
163
+ error = nil
164
+ case code
165
+ when 401
166
+ error = UnauthorizedError
167
+ when 409
168
+ error = OperationFailureException
169
+ end
170
+
171
+ error ||= case exception
172
+ when /SyntaxException/ ; SyntaxException
173
+ when /this is not a query/ ; SyntaxException
174
+ when /PropertyValueException/ ; PropertyValueException
175
+ when /BadInputException/ ; BadInputException
176
+ when /NodeNotFoundException/ ; NodeNotFoundException
177
+ when /NoSuchPropertyException/ ; NoSuchPropertyException
178
+ when /RelationshipNotFoundException/ ; RelationshipNotFoundException
179
+ when /NotFoundException/ ; NotFoundException
180
+ when /UniquePathNotUniqueException/ ; UniquePathNotUniqueException
181
+ else
182
+ NeographyError
183
+ end
184
+
185
+ raise error.new(message, code, stacktrace)
186
+ end
187
+
188
+ def parse_string_options(options)
189
+ url = URI.parse(options)
190
+ options = {
191
+ :protocol => url.scheme + "://",
192
+ :server => url.host,
193
+ :port => url.port,
194
+ :directory => url.path,
195
+ :username => url.user,
196
+ :password => url.password
197
+ }
198
+ options[:authentication] = 'basic' unless url.user.nil?
199
+ options
200
+ end
201
+
202
+ end
203
+ end