neo4j-core 3.0.0.alpha.13 → 3.0.0.alpha.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +60 -49
  3. data/lib/mydb/active_tx_log +1 -0
  4. data/lib/mydb/index/lucene-store.db +0 -0
  5. data/lib/mydb/index/lucene.log.1 +0 -0
  6. data/lib/mydb/index/lucene.log.active +0 -0
  7. data/lib/mydb/lock +0 -0
  8. data/lib/mydb/messages.log +313 -0
  9. data/lib/mydb/neostore +0 -0
  10. data/lib/mydb/neostore.id +0 -0
  11. data/lib/mydb/neostore.labeltokenstore.db +0 -0
  12. data/lib/mydb/neostore.labeltokenstore.db.id +0 -0
  13. data/lib/mydb/neostore.labeltokenstore.db.names +0 -0
  14. data/lib/mydb/neostore.labeltokenstore.db.names.id +0 -0
  15. data/lib/mydb/neostore.nodestore.db +0 -0
  16. data/lib/mydb/neostore.nodestore.db.id +0 -0
  17. data/lib/mydb/neostore.nodestore.db.labels +0 -0
  18. data/lib/mydb/neostore.nodestore.db.labels.id +0 -0
  19. data/lib/mydb/neostore.propertystore.db +0 -0
  20. data/lib/mydb/neostore.propertystore.db.arrays +0 -0
  21. data/lib/mydb/neostore.propertystore.db.arrays.id +0 -0
  22. data/lib/mydb/neostore.propertystore.db.id +0 -0
  23. data/lib/mydb/neostore.propertystore.db.index +0 -0
  24. data/lib/mydb/neostore.propertystore.db.index.id +0 -0
  25. data/lib/mydb/neostore.propertystore.db.index.keys +0 -0
  26. data/lib/mydb/neostore.propertystore.db.index.keys.id +0 -0
  27. data/lib/mydb/neostore.propertystore.db.strings +0 -0
  28. data/lib/mydb/neostore.propertystore.db.strings.id +0 -0
  29. data/lib/mydb/neostore.relationshipstore.db +0 -0
  30. data/lib/mydb/neostore.relationshipstore.db.id +0 -0
  31. data/lib/mydb/neostore.relationshiptypestore.db +0 -0
  32. data/lib/mydb/neostore.relationshiptypestore.db.id +0 -0
  33. data/lib/mydb/neostore.relationshiptypestore.db.names +0 -0
  34. data/lib/mydb/neostore.relationshiptypestore.db.names.id +0 -0
  35. data/lib/mydb/neostore.schemastore.db +0 -0
  36. data/lib/mydb/neostore.schemastore.db.id +0 -0
  37. data/lib/mydb/nioneo_logical.log.1 +0 -0
  38. data/lib/mydb/nioneo_logical.log.active +0 -0
  39. data/lib/mydb/schema/label/lucene/write.lock +0 -0
  40. data/lib/mydb/store_lock +0 -0
  41. data/lib/mydb/tm_tx_log.1 +0 -0
  42. data/lib/neo4j-core.rb +1 -2
  43. data/lib/neo4j-core/query_builder.rb +200 -0
  44. data/lib/neo4j-core/version.rb +1 -1
  45. data/lib/neo4j-embedded.rb +1 -0
  46. data/lib/neo4j-embedded/cypher_response.rb +89 -0
  47. data/lib/neo4j-embedded/cypher_response.rb~ +85 -0
  48. data/lib/neo4j-embedded/embedded_node.rb +12 -0
  49. data/lib/neo4j-embedded/embedded_node.rb~ +201 -0
  50. data/lib/neo4j-embedded/embedded_relationship.rb +8 -0
  51. data/lib/neo4j-embedded/embedded_relationship.rb~ +62 -0
  52. data/lib/neo4j-embedded/embedded_session.rb +20 -12
  53. data/lib/neo4j-embedded/embedded_session.rb~ +145 -0
  54. data/lib/neo4j-server/cypher_relationship.rb +6 -11
  55. data/lib/neo4j-server/cypher_response.rb +43 -5
  56. data/lib/neo4j-server/cypher_response.rb~ +155 -0
  57. data/lib/neo4j-server/cypher_session.rb +54 -19
  58. data/lib/neo4j/label.rb +7 -51
  59. data/lib/neo4j/node.rb +21 -19
  60. data/lib/neo4j/relationship.rb +7 -7
  61. data/lib/neo4j/session.rb +70 -28
  62. data/lib/neo4j/session.rb~ +202 -0
  63. data/neo4j-core.gemspec +0 -1
  64. metadata +49 -16
@@ -25,8 +25,7 @@ module Neo4j::Server
25
25
  def load_resource
26
26
  id = neo_id
27
27
  unless @resource_data
28
- r = @session._query_internal{ rel(id) }
29
- @resource_data = r.first_data
28
+ @resource_data = @session._query_or_fail("START n=relationship(#{id}) RETURN n", true) # r.first_data
30
29
  end
31
30
  end
32
31
 
@@ -44,21 +43,17 @@ module Neo4j::Server
44
43
 
45
44
  def get_property(key)
46
45
  id = neo_id
47
- r = @session._query_internal{rel(id)[key]}
48
- expect_response_code(r.response, 200)
49
- r.first_data
46
+ @session._query_or_fail("START n=relationship(#{id}) RETURN n.`#{key}`", true)
50
47
  end
51
48
 
52
49
  def set_property(key,value)
53
50
  id = neo_id
54
- r = @session._query_internal{rel(id)[key]=value}
55
- expect_response_code(r.response, 200)
51
+ @session._query_or_fail("START n=relationship(#{id}) SET n.`#{key}` = {value}", false, {value: value})
56
52
  end
57
53
 
58
54
  def remove_property(key)
59
55
  id = neo_id
60
- r = @session._query_internal{rel(id)[key]=:NULL}
61
- expect_response_code(r.response, 200)
56
+ @session._query_or_fail("START n=relationship(#{id}) REMOVE n.`#{key}`")
62
57
  end
63
58
 
64
59
  # (see Neo4j::Relationship#props)
@@ -86,12 +81,12 @@ module Neo4j::Server
86
81
 
87
82
  def del
88
83
  id = neo_id
89
- @session._query_internal{rel(id).del}.raise_unless_response_code(200)
84
+ @session._query("START n=relationship(#{id}) DELETE n").raise_unless_response_code(200)
90
85
  end
91
86
 
92
87
  def exist?
93
88
  id = neo_id
94
- response = @session._query_internal{rel(id)}
89
+ response = @session._query("START n=relationship(#{id}) RETURN n")
95
90
 
96
91
  if (!response.error?)
97
92
  return true
@@ -22,23 +22,61 @@ module Neo4j::Server
22
22
  def_delegator :@response, :data
23
23
  def_delegator :@response, :columns
24
24
 
25
- def initialize(response)
25
+ def initialize(response, map_return_procs, query)
26
26
  @response = response
27
+ @map_return_procs = map_return_procs
28
+ @query = query
27
29
  end
28
30
 
29
- def each()
31
+ def to_s
32
+ @query
33
+ end
34
+
35
+ def inspect
36
+ "Enumerable query: '#{@query}'"
37
+ end
38
+
39
+ def each_no_mapping
30
40
  data.each do |row|
31
41
  hash = {}
32
42
  row.each_with_index do |row, i|
33
- hash[columns[i].to_sym] = row
43
+ key = columns[i].to_sym
44
+ hash[key] = row
34
45
  end
35
46
  yield hash
36
47
  end
37
48
  end
49
+
50
+ def each_multi_column_mapping
51
+ data.each do |row|
52
+ hash = {}
53
+ row.each_with_index do |row, i|
54
+ key = columns[i].to_sym
55
+ proc = @map_return_procs[key]
56
+ hash[key] = proc ? proc.call(row) : row
57
+ end
58
+ yield hash
59
+ end
60
+ end
61
+
62
+ def each_single_column_mapping
63
+ data.each do |row|
64
+ result = @map_return_procs.call(row.first)
65
+ yield result
66
+ end
67
+ end
68
+
69
+ def each(&block)
70
+ case @map_return_procs
71
+ when NilClass then each_no_mapping &block
72
+ when Hash then each_multi_column_mapping &block
73
+ else each_single_column_mapping &block
74
+ end
75
+ end
38
76
  end
39
77
 
40
- def to_hash_enumeration
41
- HashEnumeration.new(self)
78
+ def to_hash_enumeration(map_return_procs={}, cypher='')
79
+ HashEnumeration.new(self, map_return_procs, cypher)
42
80
  end
43
81
 
44
82
  def initialize(response, uncommited = false)
@@ -0,0 +1,155 @@
1
+ module Neo4j::Server
2
+ class CypherResponse
3
+ attr_reader :data, :columns, :error_msg, :error_status, :error_code, :response
4
+
5
+ class ResponseError < StandardError
6
+ attr_reader :status, :code
7
+
8
+ def initialize(msg, status, code)
9
+ super(msg)
10
+ @status = status
11
+ @code = code
12
+ end
13
+ end
14
+
15
+
16
+ class HashEnumeration
17
+ include Enumerable
18
+ extend Forwardable
19
+ def_delegator :@response, :error_msg
20
+ def_delegator :@response, :error_status
21
+ def_delegator :@response, :error_code
22
+ def_delegator :@response, :data
23
+ def_delegator :@response, :columns
24
+
25
+ def initialize(response, map_return_procs, query)
26
+ @response = response
27
+ @map_return_procs = map_return_procs
28
+ @query = query
29
+ end
30
+
31
+ def to_s
32
+ @query
33
+ end
34
+
35
+ puts "RELOADED"
36
+ def inspect
37
+ #"Enumerable query: '#{@query}' map_return: [#{@map_return_procs.keys.join(', ')}]"
38
+ "Enumerable query: '#{@query}' map_return: [#{@map_return_procs.keys.inspect}]"
39
+ end
40
+
41
+ def each_no_mapping
42
+ data.each do |row|
43
+ hash = {}
44
+ row.each_with_index do |row, i|
45
+ key = columns[i].to_sym
46
+ hash[key] = row
47
+ end
48
+ yield hash
49
+ end
50
+ end
51
+
52
+ def each_multi_column_mapping
53
+ data.each do |row|
54
+ hash = {}
55
+ row.each_with_index do |row, i|
56
+ key = columns[i].to_sym
57
+ proc = @map_return_procs[key]
58
+ hash[key] = proc ? proc.call(row) : row
59
+ end
60
+ yield hash
61
+ end
62
+ end
63
+
64
+ def each_single_column_mapping
65
+ data.each do |row|
66
+ result = @map_return_procs.call(row.first)
67
+ yield result
68
+ end
69
+ end
70
+
71
+ def each(&block)
72
+ case @map_return_procs
73
+ when NilClass then each_no_mapping &block
74
+ when Hash then each_multi_column_mapping &block
75
+ else each_single_column_mapping &block
76
+ end
77
+ end
78
+ end
79
+
80
+ def to_hash_enumeration(map_return_procs={}, cypher='')
81
+ HashEnumeration.new(self, map_return_procs, cypher)
82
+ end
83
+
84
+ def initialize(response, uncommited = false)
85
+ @response = response
86
+ @uncommited = uncommited
87
+ end
88
+
89
+
90
+ def first_data
91
+ if uncommited?
92
+ @data.first['row'].first
93
+ else
94
+ @data[0][0]
95
+ end
96
+ end
97
+
98
+ def error?
99
+ !!@error
100
+ end
101
+
102
+ def uncommited?
103
+ @uncommited
104
+ end
105
+
106
+ def raise_unless_response_code(code)
107
+ raise "Response code #{response.code}, expected #{code} for #{response.request.path}, #{response.body}" unless response.code == code
108
+ end
109
+
110
+ def set_data(data, columns)
111
+ @data = data
112
+ @columns = columns
113
+ self
114
+ end
115
+
116
+ def set_error(error_msg, error_status, error_core)
117
+ @error = true
118
+ @error_msg = error_msg
119
+ @error_status = error_status
120
+ @error_code = error_core
121
+ self
122
+ end
123
+
124
+ def raise_error
125
+ raise "Tried to raise error without an error" unless @error
126
+ raise ResponseError.new(@error_msg, @error_status, @error_code)
127
+ end
128
+
129
+ def self.create_with_no_tx(response)
130
+ case response.code
131
+ when 200
132
+ CypherResponse.new(response).set_data(response['data'], response['columns'])
133
+ when 400
134
+ CypherResponse.new(response).set_error(response['message'], response['exception'], response['fullname'])
135
+ else
136
+ raise "Unknown response code #{response.code} for #{response.request.path.to_s}"
137
+ end
138
+ end
139
+
140
+ def self.create_with_tx(response)
141
+ raise "Unknown response code #{response.code} for #{response.request.path.to_s}" unless response.code == 200
142
+
143
+ first_result = response['results'][0]
144
+ cr = CypherResponse.new(response, true)
145
+
146
+ if (response['errors'].empty?)
147
+ cr.set_data(first_result['data'], first_result['columns'])
148
+ else
149
+ first_error = response['errors'].first
150
+ cr.set_error(first_error['message'], first_error['status'], first_error['code'])
151
+ end
152
+ cr
153
+ end
154
+ end
155
+ end
@@ -15,9 +15,8 @@ module Neo4j::Server
15
15
  # Opens a session to the database
16
16
  # @see Neo4j::Session#open
17
17
  #
18
- # @param url - defaults to 'http://localhost:7474' if not given
19
- # @params - see https://github.com/jnunemaker/httparty/blob/master/lib/httparty.rb for supported
20
- # HTTParty options
18
+ # @param [String] endpoint_url - the url to the neo4j server, defaults to 'http://localhost:7474'
19
+ # @param [Hash] params - see https://github.com/jnunemaker/httparty/blob/master/lib/httparty.rb for supported HTTParty options
21
20
  def self.open(endpoint_url=nil, params = {})
22
21
  endpoint = Neo4jServerEndpoint.new(params)
23
22
  url = endpoint_url || 'http://localhost:7474'
@@ -36,10 +35,19 @@ module Neo4j::Server
36
35
  Neo4j::Session.register(self)
37
36
  initialize_resource(data_url)
38
37
  Neo4j::Session._notify_listeners(:session_available, self)
38
+ @query_builder = Neo4j::Core::QueryBuilder.new
39
39
  end
40
40
 
41
41
  def to_s
42
- "CypherSession #{@resource_url}"
42
+ "#{self.class} url: '#{@resource_url}'"
43
+ end
44
+
45
+ def inspect
46
+ "#{to_s} version: '#{version}'"
47
+ end
48
+
49
+ def version
50
+ resource_data ? resource_data['neo4j_version'] : ''
43
51
  end
44
52
 
45
53
  def initialize_resource(data_url)
@@ -109,7 +117,7 @@ module Neo4j::Server
109
117
 
110
118
  def find_all_nodes(label_name)
111
119
  response = _query_or_fail("MATCH (n:`#{label_name}`) RETURN ID(n)")
112
- search_result_to_enumerable(response)
120
+ search_result_to_enumerable_first_column(response)
113
121
  end
114
122
 
115
123
  def find_nodes(label_name, key, value)
@@ -120,20 +128,20 @@ module Neo4j::Server
120
128
  WHERE n.#{key} = #{value}
121
129
  RETURN ID(n)
122
130
  CYPHER
123
- search_result_to_enumerable(response)
131
+ search_result_to_enumerable_first_column(response)
124
132
  end
125
133
 
126
- def query(*params, &query_dsl)
127
- result = super
134
+ def query(*params)
135
+ query_hash = @query_builder.to_query_hash(params, :id_to_node)
136
+ cypher = @query_builder.to_cypher(query_hash)
137
+
138
+ result = _query(cypher, query_hash[:params])
128
139
  if result.error?
129
140
  raise Neo4j::Session::CypherError.new(result.error_msg, result.error_code, result.error_status)
130
141
  end
131
- result.to_hash_enumeration
132
- end
133
142
 
134
- # TODO remove this function and do not use cypher DSL internally
135
- def _query_internal(*params, &query_dsl)
136
- super_query(*params, &query_dsl)
143
+ map_return_procs = @query_builder.to_map_return_procs(query_hash)
144
+ result.to_hash_enumeration(map_return_procs, cypher)
137
145
  end
138
146
 
139
147
  def _query_or_fail(q, single_row = false, params=nil)
@@ -142,10 +150,6 @@ module Neo4j::Server
142
150
  single_row ? response.first_data : response
143
151
  end
144
152
 
145
- def query_default_return
146
- " RETURN ID(n)"
147
- end
148
-
149
153
  def _query(q, params=nil)
150
154
  curr_tx = Neo4j::Transaction.current
151
155
  if (curr_tx)
@@ -158,9 +162,8 @@ module Neo4j::Server
158
162
  end
159
163
  end
160
164
 
161
- def search_result_to_enumerable(response)
165
+ def search_result_to_enumerable_first_column(response)
162
166
  return [] unless response.data
163
-
164
167
  Enumerator.new do |yielder|
165
168
  response.data.each do |data|
166
169
  yielder << CypherNode.new(self, data[0]).wrapper
@@ -169,7 +172,39 @@ module Neo4j::Server
169
172
  end
170
173
 
171
174
 
175
+ def map_column(key, map, data)
176
+ case map[key]
177
+ when :node
178
+ CypherNode.new(self, data).wrapper
179
+ when :rel, :relationship
180
+ CypherRelationship.new(self, data)
181
+ else
182
+ data
183
+ end
184
+ end
185
+
172
186
 
187
+ def search_result_to_enumerable(response, ret, map)
188
+ return [] unless response.data
189
+
190
+ if (ret.size == 1)
191
+ Enumerator.new do |yielder|
192
+ response.data.each do |data|
193
+ yielder << map_column(key, map, data[0])
194
+ end
195
+ end
173
196
 
197
+ else
198
+ Enumerator.new do |yielder|
199
+ response.data.each do |data|
200
+ hash = {}
201
+ ret.each_with_index do |key, i|
202
+ hash[key] = map_column(key, map, data[i])
203
+ end
204
+ yielder << hash
205
+ end
206
+ end
207
+ end
208
+ end
174
209
  end
175
210
  end
data/lib/neo4j/label.rb CHANGED
@@ -3,6 +3,7 @@ module Neo4j
3
3
  # See Neo4j::Node how to create and delete nodes
4
4
  # @see http://docs.neo4j.org/chunked/milestone/graphdb-neo4j-labels.html
5
5
  class Label
6
+ class InvalidQueryError < StandardError; end
6
7
 
7
8
  # @abstract
8
9
  def name
@@ -61,70 +62,25 @@ module Neo4j
61
62
  class << self
62
63
  include Neo4j::Core::CypherTranslator
63
64
 
65
+ # Returns a label of given name that can be used to specifying constraints
66
+ # @param [Symbol,String] name the name of the label
64
67
  def create(name, session = Neo4j::Session.current)
65
68
  session.create_label(name)
66
69
  end
67
70
 
68
- def query(label_name, query, session = Neo4j::Session.current)
69
- cypher = "MATCH (n:`#{label_name}`)"
70
- cypher += condition_to_cypher(query) if query[:conditions] && !query[:conditions].empty?
71
- cypher += session.query_default_return
72
- cypher += order_to_cypher(query) if query[:order]
73
-
74
- response = session._query_or_fail(cypher)
75
- session.search_result_to_enumerable(response) # TODO make it work in Embedded and refactor
76
- end
77
-
78
71
 
72
+ # @return [Enumerable<Neo4j::Node>] all nodes having given label. Nodes can be wrapped in your own model ruby classes.
79
73
  def find_all_nodes(label_name, session = Neo4j::Session.current)
80
74
  session.find_all_nodes(label_name)
81
75
  end
82
76
 
77
+ # @return [Enumerable<Neo4j::Node>] all nodes having given label and properties. Nodes can be wrapped in your own model ruby classes.
83
78
  def find_nodes(label_name, key, value, session = Neo4j::Session.current)
84
79
  session.find_nodes(label_name, key, value)
85
80
  end
86
81
 
87
- private
88
-
89
- def condition_to_cypher(query)
90
- conditions = query[:conditions]
91
- " WHERE " + conditions.keys.map do |k|
92
- value = conditions[k]
93
- if value.is_a? Regexp
94
- pattern = (value.casefold? ? "(?i)" : "") + value.source
95
- "n.#{k}=~#{escape_value(pattern.gsub(/\\/, '\\\\\\'))}"
96
- else
97
- "n.#{k}=#{escape_value(conditions[k])}"
98
- end
99
- end.join(" AND ")
100
- end
101
-
102
- def order_to_cypher(query)
103
- cypher = " ORDER BY "
104
- order = query[:order]
105
-
106
- handleHash = Proc.new do |hash|
107
- if (hash.is_a?(Hash))
108
- k, v = hash.first
109
- raise "only :asc or :desc allowed in order, got #{query.inspect}" unless [:asc, :desc].include?(v)
110
- v.to_sym == :asc ? "n.`#{k}`" : "n.`#{k}` DESC"
111
- else
112
- "n.`#{hash}`" unless hash.is_a?(Hash)
113
- end
114
- end
115
-
116
- case order
117
- when Array
118
- cypher += order.map(&handleHash).join(', ')
119
- when Hash
120
- cypher += handleHash.call(order)
121
- else
122
- cypher += "n.`#{order}`"
123
- end
124
-
125
- cypher
126
- end
127
82
  end
83
+
128
84
  end
129
85
 
130
- end
86
+ end