neo4j-core 2.0.0.alpha.1-java → 2.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/Gemfile +2 -2
  2. data/README.rdoc +161 -13
  3. data/config/neo4j/config.yml +1 -1
  4. data/lib/db/active_tx_log +1 -0
  5. data/lib/db/index/lucene-store.db +0 -0
  6. data/lib/db/index/lucene.log.active +0 -0
  7. data/lib/db/messages.log +2299 -0
  8. data/lib/db/neostore +0 -0
  9. data/lib/db/neostore.id +0 -0
  10. data/lib/db/neostore.nodestore.db +0 -0
  11. data/lib/db/neostore.nodestore.db.id +0 -0
  12. data/lib/db/neostore.propertystore.db +0 -0
  13. data/lib/db/neostore.propertystore.db.arrays +0 -0
  14. data/lib/db/neostore.propertystore.db.arrays.id +0 -0
  15. data/lib/db/neostore.propertystore.db.id +0 -0
  16. data/lib/db/neostore.propertystore.db.index +0 -0
  17. data/lib/db/neostore.propertystore.db.index.id +0 -0
  18. data/lib/db/neostore.propertystore.db.index.keys +0 -0
  19. data/lib/db/neostore.propertystore.db.index.keys.id +0 -0
  20. data/lib/db/neostore.propertystore.db.strings +0 -0
  21. data/lib/db/neostore.propertystore.db.strings.id +0 -0
  22. data/lib/db/neostore.relationshipstore.db +0 -0
  23. data/lib/db/neostore.relationshipstore.db.id +0 -0
  24. data/lib/db/neostore.relationshiptypestore.db +0 -0
  25. data/lib/db/neostore.relationshiptypestore.db.id +0 -0
  26. data/lib/db/neostore.relationshiptypestore.db.names +0 -0
  27. data/lib/db/neostore.relationshiptypestore.db.names.id +0 -0
  28. data/lib/db/nioneo_logical.log.active +0 -0
  29. data/lib/db/tm_tx_log.1 +0 -0
  30. data/lib/neo4j-core.rb +20 -3
  31. data/lib/neo4j-core/cypher/cypher.rb +1033 -0
  32. data/lib/neo4j-core/cypher/result_wrapper.rb +48 -0
  33. data/lib/neo4j-core/database.rb +4 -5
  34. data/lib/neo4j-core/event_handler.rb +1 -1
  35. data/lib/neo4j-core/hash_with_indifferent_access.rb +165 -0
  36. data/lib/neo4j-core/index/class_methods.rb +27 -41
  37. data/lib/neo4j-core/index/index.rb +3 -4
  38. data/lib/neo4j-core/index/index_config.rb +30 -23
  39. data/lib/neo4j-core/index/indexer.rb +65 -53
  40. data/lib/neo4j-core/index/indexer_registry.rb +2 -2
  41. data/lib/neo4j-core/index/lucene_query.rb +53 -42
  42. data/lib/neo4j-core/index/unique_factory.rb +54 -0
  43. data/lib/neo4j-core/node/class_methods.rb +4 -4
  44. data/lib/neo4j-core/node/node.rb +1 -8
  45. data/lib/neo4j-core/property/java.rb +59 -0
  46. data/lib/neo4j-core/property/property.rb +1 -3
  47. data/lib/neo4j-core/relationship/relationship.rb +8 -10
  48. data/lib/neo4j-core/rels/rels.rb +9 -4
  49. data/lib/neo4j-core/rels/traverser.rb +13 -27
  50. data/lib/neo4j-core/traversal/prune_evaluator.rb +2 -2
  51. data/lib/neo4j-core/traversal/traverser.rb +122 -27
  52. data/lib/neo4j-core/version.rb +1 -1
  53. data/lib/neo4j-core/wrapper/class_methods.rb +22 -0
  54. data/lib/neo4j-core/wrapper/wrapper.rb +20 -0
  55. data/lib/neo4j/algo.rb +300 -0
  56. data/lib/neo4j/config.rb +3 -6
  57. data/lib/neo4j/cypher.rb +180 -0
  58. data/lib/neo4j/neo4j.rb +51 -23
  59. data/lib/neo4j/node.rb +27 -0
  60. data/lib/neo4j/relationship.rb +25 -0
  61. data/lib/test.rb~ +27 -0
  62. data/neo4j-core.gemspec +2 -2
  63. metadata +44 -11
  64. data/lib/neo4j-core/type_converters/type_converters.rb +0 -287
  65. data/lib/neo4j-core/version.rb~ +0 -3
  66. data/lib/test.rb +0 -27
@@ -17,55 +17,21 @@ module Neo4j
17
17
 
18
18
 
19
19
  def to_s
20
- "Indexer @#{object_id} index on: [#{@config.fields.map{|f| @config.numeric?(f)? "#{f} (numeric)" : f}.join(', ')}]"
20
+ "Indexer @#{object_id} index on: [#{@config.fields.map { |f| @config.numeric?(f) ? "#{f} (numeric)" : f }.join(', ')}]"
21
21
  end
22
22
 
23
23
  # Add an index on a field so that it will be automatically updated by neo4j transactional events.
24
+ # Notice that if you want to numerical range queries then you should specify a field_type of either Fixnum or Float.
25
+ # The index type will by default be <tt>:exact</tt>.
26
+ # Index on property arrays are supported.
24
27
  #
25
- # The index method takes an optional configuration hash which allows you to:
26
- #
27
- # @example Add an index on an a property
28
- #
29
- # class Person
30
- # include Neo4j::NodeMixin
31
- # index :name
32
- # end
33
- #
34
- # When the property name is changed/deleted or the node created it will keep the lucene index in sync.
35
- # You can then perform a lucene query like this: Person.find('name: andreas')
36
- #
37
- # @example Add index on other nodes.
38
- #
39
- # class Person
40
- # include Neo4j::NodeMixin
41
- # has_n(:friends).to(Contact)
42
- # has_n(:known_by).from(:friends)
43
- # index :user_id, :via => :known_by
44
- # end
45
- #
46
- # Notice that you *must* specify an incoming relationship with the via key, as shown above.
47
- # In the example above an index <tt>user_id</tt> will be added to all Person nodes which has a <tt>friends</tt> relationship
48
- # that person with that user_id. This allows you to do lucene queries on your friends properties.
49
- #
50
- # @example Set the type value to index
51
- #
52
- # class Person
53
- # include Neo4j::NodeMixin
54
- # property :height, :weight, :type => Float
55
- # index :height, :weight
56
- # end
57
- #
58
- # By default all values will be indexed as Strings.
59
- # If you want for example to do a numerical range query you must tell Neo4j.rb to index it as a numeric value.
60
- # You do that with the key <tt>type</tt> on the property.
61
- #
62
- # Supported values for <tt>:type</tt> is <tt>String</tt>, <tt>Float</tt>, <tt>Date</tt>, <tt>DateTime</tt> and <tt>Fixnum</tt>
63
- #
64
- # === For more information
28
+ # @example
29
+ # MyIndex.index(:age, :field_type => Fixnum) # default :exact
30
+ # MyIndex.index(:wheels, :field_type => Fixnum)
31
+ # MyIndex.index(:description, :type => :fulltext)
65
32
  #
66
33
  # @see Neo4j::Core::Index::LuceneQuery
67
34
  # @see #find
68
- #
69
35
  def index(*args)
70
36
  @config.index(args)
71
37
  end
@@ -96,11 +62,18 @@ module Neo4j
96
62
  # @see #index
97
63
  def add_index(entity, field, value)
98
64
  return false unless index?(field)
99
- conv_value = indexed_value_for(field, value)
65
+ if (java_array?(value))
66
+ conv_value = value.map{|x| indexed_value_for(field, x)}.to_java(Java::OrgNeo4jIndexLucene::ValueContext)
67
+ else
68
+ conv_value = indexed_value_for(field, value)
69
+ end
100
70
  index = index_for_field(field.to_s)
101
71
  index.add(entity, field, conv_value)
102
72
  end
103
73
 
74
+ def java_array?(value)
75
+ value.respond_to?(:java_class) && value.java_class.to_s[0..0] == '['
76
+ end
104
77
 
105
78
  # Removes an index on the given entity
106
79
  # This is normally not needed since you can instead declare an index which will automatically keep
@@ -108,6 +81,7 @@ module Neo4j
108
81
  # @see #index
109
82
  def rm_index(entity, field, value)
110
83
  return false unless index?(field)
84
+ #return value.each {|x| rm_index(entity, field, x)} if value.respond_to?(:each)
111
85
  index_for_field(field).remove(entity, field, value)
112
86
  end
113
87
 
@@ -120,23 +94,44 @@ module Neo4j
120
94
  # (by Rack).
121
95
  #
122
96
  # @example with a block
97
+ # Person.find('name: kalle') {|query| puts "First item #{query.first}"}
123
98
  #
124
- # Person.find('name: kalle') {|query| puts "#{[*query].join(', )"}
125
- #
126
- # @example
127
- #
99
+ # @example using an exact lucene index
128
100
  # query = Person.find('name: kalle')
129
101
  # puts "First item #{query.first}"
130
102
  # query.close
131
103
  #
132
- # @return [Neo4j::Core::Index::LuceneQuery] a query object
104
+ # @example using an fulltext lucene index
105
+ # query = Person.find('name: kalle', :type => :fulltext)
106
+ # puts "First item #{query.first}"
107
+ # query.close
108
+ #
109
+ # @example Sorting, descending by one property
110
+ # Person.find({:name => 'kalle'}, :sort => {:name => :desc})
111
+ #
112
+ # @example Sorting using the builder pattern
113
+ # Person.find(:name => 'kalle').asc(:name)
114
+ #
115
+ # @example Searching by a set of values, OR search
116
+ # Person.find(:name => ['kalle', 'sune', 'jimmy'])
117
+ #
118
+ # @example Compound queries and Range queries
119
+ # Person.find('name: pelle').and(:age).between(2, 5)
120
+ # Person.find(:name => 'kalle', :age => (2..5))
121
+ # Person.find("name: 'asd'").and(:wheels => 8)
122
+ #
123
+ # @example Using the lucene java object
124
+ # # using the Neo4j query method directly
125
+ # # see, http://api.neo4j.org/1.6.1/org/neo4j/graphdb/index/ReadableIndex.html#query(java.lang.Object)
126
+ # MyIndex.find('description: "hej"', :type => :fulltext, :wrapped => false).get_single
127
+ #
128
+ # @param [String, Hash] query the lucene query
129
+ # @param [Hash] params lucene configuration parameters
130
+ # @return [Neo4j::Core::Index::LuceneQuery] a query object which uses the builder pattern for creating compound and sort queries.
131
+ # @note You must specify the index type <tt>:fulltext<tt>) if the property is index using that index (default is <tt>:exact</tt>)
133
132
  def find(query, params = {})
134
133
  index = index_for_type(params[:type] || :exact)
135
- if query.is_a?(Hash) && (query.include?(:conditions) || query.include?(:sort))
136
- params.merge! query.reject { |k, _| k == :conditions }
137
- query.delete(:sort)
138
- query = query.delete(:conditions) if query.include?(:conditions)
139
- end
134
+ query.delete(:sort) if query.is_a?(Hash) && query.include?(:sort)
140
135
  query = (params[:wrapped].nil? || params[:wrapped]) ? LuceneQuery.new(index, @config, query, params) : index.query(query)
141
136
 
142
137
  if block_given?
@@ -151,6 +146,23 @@ module Neo4j
151
146
  end
152
147
  end
153
148
 
149
+ # Add the entity to this index for the given key/value pair if this particular key/value pair doesn't already exist.
150
+ # This ensures that only one entity will be associated with the key/value pair even if multiple transactions are trying to add it at the same time.
151
+ # One of those transactions will win and add it while the others will block, waiting for the winning transaction to finish.
152
+ # If the winning transaction was successful these other transactions will return the associated entity instead of adding it.
153
+ # If it wasn't successful the waiting transactions will begin a new race to add it.
154
+ #
155
+ # @param [Neo4j::Node, Neo4j::Relationship] entity the entity (i.e Node or Relationship) to associate the key/value pair with.
156
+ # @param [String, Symbol] key the key in the key/value pair to associate with the entity.
157
+ # @param [String, Fixnum, Float] value the value in the key/value pair to associate with the entity.
158
+ # @param [Symbol] index_type the type of lucene index
159
+ # @return [nil, Neo4j:Node, Neo4j::Relationship] the previously indexed entity, or nil if no entity was indexed before (and the specified entity was added to the index).
160
+ # @see Neo4j::Core::Index::UniqueFactory as an alternative which probably simplify creating unique entities
161
+ def put_if_absent(entity, key, value, index_type = :exact)
162
+ index = index_for_type(index_type)
163
+ index.put_if_absent(entity, key.to_s, value)
164
+ end
165
+
154
166
  # Delete all index configuration. No more automatic indexing will be performed
155
167
  def rm_index_config
156
168
  @config.rm_index_config
@@ -7,7 +7,7 @@ module Neo4j
7
7
  end
8
8
 
9
9
  def delete_all_indexes
10
- @indexers.values.each { |i| i.rm_index_type }
10
+ @indexers.each { |i| i.rm_index_type }
11
11
  end
12
12
 
13
13
  def register(indexer)
@@ -16,7 +16,7 @@ module Neo4j
16
16
  end
17
17
 
18
18
  def indexers_for(props)
19
- Enumerable::Enumerator.new(self, :each_indexer, props)
19
+ Enumerator.new(self, :each_indexer, props)
20
20
  end
21
21
 
22
22
  def each_indexer(props)
@@ -39,11 +39,7 @@ module Neo4j
39
39
  @query = query
40
40
  @index_config = index_config
41
41
  @params = params
42
-
43
- if params.include?(:sort)
44
- @order = {}
45
- params[:sort].each_pair { |k, v| @order[k] = (v == :desc) }
46
- end
42
+ @order = params[:sort] if params.include?(:sort)
47
43
  end
48
44
 
49
45
  # Implements the Ruby +Enumerable+ interface
@@ -85,30 +81,26 @@ module Neo4j
85
81
  # Performs a range query
86
82
  # Notice that if you don't specify a type when declaring a property a String range query will be performed.
87
83
  #
88
- def between(lower, upper, lower_incusive=false, upper_inclusive=false)
84
+ def between(lower, upper, lower_inclusive=false, upper_inclusive=false)
89
85
  raise "Expected a symbol. Syntax for range queries example: index(:weight).between(a,b)" unless Symbol === @query
90
- # raise "Can't only do range queries on Neo4j::NodeMixin, Neo4j::Model, Neo4j::RelationshipMixin" unless @decl_props
91
- # check that we perform a range query on the same values as we have declared with the property :key, :type => ...
92
- type = @index_config.decl_type_on(@query)
93
- raise "find(#{@query}).between(#{lower}, #{upper}): #{lower} not a #{type}" if type && !type === lower.class
94
- raise "find(#{@query}).between(#{lower}, #{upper}): #{upper} not a #{type}" if type && !type === upper.class
95
-
96
- # Make it possible to convert those values
97
- @query = range_query(@query, lower, upper, lower_incusive, upper_inclusive)
86
+ @query = range_query(@query, lower, upper, lower_inclusive, upper_inclusive)
98
87
  self
99
88
  end
100
89
 
101
- def range_query(field, lower, upper, lower_incusive, upper_inclusive)
102
- lower = TypeConverters.convert(lower)
103
- upper = TypeConverters.convert(upper)
90
+ def range_query(field, lower, upper, lower_inclusive, upper_inclusive)
91
+ type = @index_config.field_type(field)
92
+ raise "no index on field #{field}" unless type
93
+ # check that we perform a range query on the same values as we have declared with the property :key, :type => ...
94
+ raise "find(#{field}).between(#{lower}, #{upper}): #{lower} not a #{type}" unless type == lower.class
95
+ raise "find(#{field}).between(#{lower}, #{upper}): #{upper} not a #{type}" unless type == upper.class
104
96
 
105
97
  case lower
106
98
  when Fixnum
107
- Java::OrgApacheLuceneSearch::NumericRangeQuery.new_long_range(field.to_s, lower, upper, lower_incusive, upper_inclusive)
99
+ Java::OrgApacheLuceneSearch::NumericRangeQuery.new_long_range(field.to_s, lower, upper, lower_inclusive, upper_inclusive)
108
100
  when Float
109
- Java::OrgApacheLuceneSearch::NumericRangeQuery.new_double_range(field.to_s, lower, upper, lower_incusive, upper_inclusive)
101
+ Java::OrgApacheLuceneSearch::NumericRangeQuery.new_double_range(field.to_s, lower, upper, lower_inclusive, upper_inclusive)
110
102
  else
111
- Java::OrgApacheLuceneSearch::TermRangeQuery.new(field.to_s, lower, upper, lower_incusive, upper_inclusive)
103
+ Java::OrgApacheLuceneSearch::TermRangeQuery.new(field.to_s, lower, upper, lower_inclusive, upper_inclusive)
112
104
  end
113
105
  end
114
106
 
@@ -156,19 +148,28 @@ module Neo4j
156
148
  # Sort descending the given fields.
157
149
  # @param [Symbol] fields it should sort
158
150
  def desc(*fields)
159
- @order = fields.inject(@order || {}) { |memo, field| memo[field] = true; memo }
151
+ @order ||= []
152
+ @order += fields.map { |f| [f, :desc] }
160
153
  self
161
154
  end
162
155
 
163
156
  # Sort ascending the given fields.
164
157
  # @param [Symbol] fields it should sort
165
158
  def asc(*fields)
166
- @order = fields.inject(@order || {}) { |memo, field| memo[field] = false; memo }
159
+ @order ||= []
160
+ @order += fields.map { |f| [f, :asc] }
167
161
  self
168
162
  end
169
163
 
170
164
  protected
171
165
 
166
+ def parse_query(query)
167
+ version = Java::OrgApacheLuceneUtil::Version::LUCENE_30
168
+ analyzer = Java::OrgApacheLuceneAnalysisStandard::StandardAnalyzer.new(version)
169
+ parser = Java::org.apache.lucene.queryParser.QueryParser.new(version, 'name', analyzer)
170
+ parser.parse(query)
171
+ end
172
+
172
173
  def build_and_query(query)
173
174
  build_composite_query(@left_and_query.build_query, query, Java::OrgApacheLuceneSearch::BooleanClause::Occur::MUST)
174
175
  end
@@ -179,6 +180,9 @@ module Neo4j
179
180
 
180
181
  def build_not_query(query)
181
182
  right_query = @right_not_query.build_query
183
+ query = parse_query(query) if query.is_a?(String)
184
+ right_query = parse_query(right_query) if right_query.is_a?(String)
185
+
182
186
  composite_query = Java::OrgApacheLuceneSearch::BooleanQuery.new
183
187
  composite_query.add(query, Java::OrgApacheLuceneSearch::BooleanClause::Occur::MUST_NOT)
184
188
  composite_query.add(right_query, Java::OrgApacheLuceneSearch::BooleanClause::Occur::MUST)
@@ -186,31 +190,27 @@ module Neo4j
186
190
  end
187
191
 
188
192
  def build_composite_query(left_query, right_query, operator) #:nodoc:
193
+ left_query = parse_query(left_query) if left_query.is_a?(String)
194
+ right_query = parse_query(right_query) if right_query.is_a?(String)
189
195
  composite_query = Java::OrgApacheLuceneSearch::BooleanQuery.new
190
- version = Java::OrgApacheLuceneUtil::Version::LUCENE_35
191
- analyzer = org.apache.lucene.analysis.standard::StandardAnalyzer.new(version)
192
- parser = Java::org.apache.lucene.queryParser.QueryParser.new(version,'name', analyzer )
193
-
194
- left_query = parser.parse(left_query) if left_query.is_a?(String)
195
- right_query = parser.parse(right_query) if right_query.is_a?(String)
196
-
197
196
  composite_query.add(left_query, operator)
198
197
  composite_query.add(right_query, operator)
199
198
  composite_query
200
199
  end
201
200
 
202
201
  def build_sort_query(query) #:nodoc:
203
- java_sort_fields = @order.keys.inject([]) do |memo, field|
204
- decl_type = @index_config.decl_type_on(field)
202
+ java_sort_fields = @order.inject([]) do |memo, val|
203
+ field = val[0]
204
+ field_type = @index_config.field_type(field)
205
205
  type = case
206
- when Float == decl_type
206
+ when Float == field_type
207
207
  Java::OrgApacheLuceneSearch::SortField::DOUBLE
208
- when Fixnum == decl_type || DateTime == decl_type || Date == decl_type || Time == decl_type
208
+ when Fixnum == field_type
209
209
  Java::OrgApacheLuceneSearch::SortField::LONG
210
210
  else
211
211
  Java::OrgApacheLuceneSearch::SortField::STRING
212
212
  end
213
- memo << Java::OrgApacheLuceneSearch::SortField.new(field.to_s, type, @order[field])
213
+ memo << Java::OrgApacheLuceneSearch::SortField.new(field.to_s, type, val[1] == :desc)
214
214
  end
215
215
  sort = Java::OrgApacheLuceneSearch::Sort.new(*java_sort_fields)
216
216
  Java::OrgNeo4jIndexLucene::QueryContext.new(query).sort(sort)
@@ -220,18 +220,29 @@ module Neo4j
220
220
  and_query = Java::OrgApacheLuceneSearch::BooleanQuery.new
221
221
 
222
222
  query.each_pair do |key, value|
223
- type = @index_config && @index_config[key.to_sym] && @index_config[key.to_sym][:type]
224
- if !type.nil? && type != String
223
+ type = @index_config.field_type(key)
224
+ if type != String
225
225
  if Range === value
226
- and_query.add(range_query(key, value.first, value.last, true, !value.exclude_end?), Java::OrgApacheLuceneIndex::BooleanClause::Occur::MUST)
226
+ and_query.add(range_query(key, value.first, value.last, true, !value.exclude_end?), Java::OrgApacheLuceneSearch::BooleanClause::Occur::MUST)
227
+ elsif Array === value
228
+ value.each do |v|
229
+ and_query.add(range_query(key, v, v, true, true), Java::OrgApacheLuceneSearch::BooleanClause::Occur::SHOULD)
230
+ end
227
231
  else
228
- and_query.add(range_query(key, value, value, true, true), Java::OrgApacheLuceneIndex::BooleanClause::Occur::MUST)
232
+ and_query.add(range_query(key, value, value, true, true), Java::OrgApacheLuceneSearch::BooleanClause::Occur::MUST)
229
233
  end
230
234
  else
231
- conv_value = type ? TypeConverters.convert(value) : value.to_s
232
- term = Java::OrgApacheLuceneIndex::Term.new(key.to_s, conv_value)
233
- term_query = Java::OrgApacheLuceneIndex::TermQuery.new(term)
234
- and_query.add(term_query, Java::OrgApacheLuceneIndex::BooleanClause::Occur::MUST)
235
+ if Array === value
236
+ value.each do |v|
237
+ term = Java::OrgApacheLuceneIndex::Term.new(key.to_s, v.to_s)
238
+ term_query = Java::OrgApacheLuceneSearch::TermQuery.new(term)
239
+ and_query.add(term_query, Java::OrgApacheLuceneSearch::BooleanClause::Occur::SHOULD)
240
+ end
241
+ else
242
+ term = Java::OrgApacheLuceneIndex::Term.new(key.to_s, value.to_s)
243
+ term_query = Java::OrgApacheLuceneSearch::TermQuery.new(term)
244
+ and_query.add(term_query, Java::OrgApacheLuceneSearch::BooleanClause::Occur::MUST)
245
+ end
235
246
  end
236
247
  end
237
248
  and_query
@@ -0,0 +1,54 @@
1
+ module Neo4j
2
+ module Core
3
+
4
+ module Index
5
+
6
+ # A Utility class that can be used to make it easier to create unique entities. It uses {Neo4j::Core::Index::Indexer#put_if_absent}.
7
+ #
8
+ # @see Indexer#put_if_absent
9
+ #
10
+ # @example
11
+ # index = index_for_type(:exact)
12
+ # Neo4j::Core::Index::UniqueFactory.new(:email, index) { |k,v| Neo4j::Node.new(k => v) }.get_or_create(:email, 'foo@gmail.com')
13
+ #
14
+ class UniqueFactory
15
+ # @param [Symbol] key only one key is possible
16
+ # @param [Java::Neo4j] index the lucene index (see #index_for_type)
17
+ # @yield a proc for initialize each created entity
18
+ def initialize(key, index, &entity_creator_block)
19
+ @key = key
20
+ @index = index
21
+ @entity_creator_block = entity_creator_block || Proc.new{|k,v| Neo4j::Node.new(key.to_s => v)}
22
+ end
23
+
24
+ # Get the indexed entity, creating it (exactly once) if no indexed entity exists.
25
+ # There must be an index on the key
26
+ # @param [Symbol] key the key to find the entity under in the index.
27
+ # @param [String, Fixnum, Float] value the value the key is mapped to for the entity in the index.
28
+ # @param [Hash] props optional properties that the entity will have if created
29
+ # @yield optional, make it possible to initialize the created node in a block
30
+ def get_or_create(key, value, props=nil, &init_block)
31
+ tx = Neo4j::Transaction.new
32
+ result = @index.get(key.to_s, value).get_single
33
+ return result if result
34
+
35
+ created = @entity_creator_block.call(key,value)
36
+ result = @index.put_if_absent(created._java_entity, key.to_s, value)
37
+ if result.nil?
38
+ props.each_pair{|k,v| created[k.to_s] = v} if props
39
+ init_block.call(result) if init_block
40
+ result = created
41
+ else
42
+ created.del
43
+ end
44
+ tx.success
45
+ result
46
+ ensure
47
+ tx.finish
48
+ end
49
+
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -61,11 +61,11 @@ module Neo4j
61
61
  end
62
62
 
63
63
  # Loads a node or wrapped node given a native java node or an id.
64
- # If there is a Ruby wrapper for the node then it will create a Ruby object that will
65
- # wrap the java node (see Neo4j::NodeMixin).
66
- # To implement a wrapper you must implement a wrapper class method in the Neo4j::Node or Neo4j::Relationship.
64
+ # If there is a Ruby wrapper for the node then it will create and return a Ruby object that will
65
+ # wrap the java node.
67
66
  #
68
- # @return [Object, nil] If the node does not exist it will return nil otherwise the loaded node or wrapped node.
67
+ # @param [nil, #to_i] node_id the neo4j node id
68
+ # @return [Object, Neo4j::Node, nil] If the node does not exist it will return nil otherwise the loaded node or wrapped node.
69
69
  def load(node_id, db = Neo4j.started_db)
70
70
  node = _load(node_id, db)
71
71
  node && node.wrapper
@@ -31,14 +31,7 @@ module Neo4j
31
31
  Neo4j::Node.exist?(self)
32
32
  end
33
33
 
34
- # Tries to load the wrapper object for this node by calling the class #wrapper method.
35
- # This allows you to create a custom Ruby wrapper class around the Neo4j::Node.
36
- # This is for example done in the <tt>neo4j<//t> ruby gem <tt>Neo4j::NodeMixin</tt>
37
- # @return a wrapper object or self
38
- def wrapper
39
- self.class.respond_to?(:wrapper) ? self.class.wrapper(node) : self
40
- end
41
-
34
+ # Overrides the class so that the java object feels like a Ruby object.
42
35
  def class
43
36
  Neo4j::Node
44
37
  end
@@ -0,0 +1,59 @@
1
+ module Neo4j
2
+ module Core
3
+ module Property
4
+ # This module is only used for documentation purpose
5
+ # It simplify declares the java methods which are available Java org.neo4j.graphdb.PropertyContainer
6
+ # @see http://api.neo4j.org/1.6.1/org/neo4j/graphdb/PropertyContainer.html
7
+ module Java
8
+
9
+
10
+ # Get the GraphDatabaseService that this Node or Relationship belongs to.
11
+ # @return [Java::Neo4jGraphdbGraphDatabaseService]
12
+ def graph_database
13
+ end
14
+
15
+ # Returns the property value associated with the given key, or a default value.
16
+ # The value is of one of the valid property types, i.e. a Java primitive, a String or an array of any of the valid types.
17
+ # If there's no property associated with key an unchecked exception is raised.
18
+ # The idiomatic way to avoid an exception for an unknown key and instead get null back is to use a default value: Object valueOrNull = nodeOrRel.getProperty( key, null )
19
+ # @param [String] key the property key
20
+ # @param [String] default_value the default value that will be returned if no property value was associated with the given key
21
+ # @return [String,Fixnum,Boolean,Float,Array] ]the property value associated with the given key.
22
+ # @raise an exception if not given a default value and there is no property for the given key
23
+ # @see Neo4j::Core:Property#[]
24
+ def get_property(key, default_value = nil)
25
+ end
26
+
27
+ # @return all existing property keys, or an empty iterable if this property container has no properties.
28
+ def property_keys
29
+ end
30
+
31
+
32
+ # Removes the property associated with the given key and returns the old value.
33
+ # @param [String] key the name of the property
34
+ # @return [String,Fixnum,Boolean,Float,Array, nil] The old value or <tt>nil</tt> if there's no property associated with the key.
35
+ def remove_property(key)
36
+ end
37
+
38
+ # Sets the property value for the given key to value.
39
+ # The property value must be one of the valid property types, i.e:
40
+ # * boolean or boolean[]
41
+ # * byte or byte[]
42
+ # * short or short[]
43
+ # * int or int[]
44
+ # * long or long[]
45
+ # * float or float[]
46
+ # * double or double[]
47
+ # * char or char[]
48
+ # * java.lang.String or String[]
49
+ # Notice that JRuby does map Ruby primitive object (e.g. Fixnum) to java primitives automatically.
50
+ # Also, nil is not an accepted property value.
51
+ # @param [String] key the property key
52
+ # @param [String,Fixnum,Boolean,Float,Array] value
53
+ # @see Neo4j::Core::Property#[]=
54
+ def set_property(key, value)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end