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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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