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.
- data/Gemfile +2 -2
- data/README.rdoc +161 -13
- data/config/neo4j/config.yml +1 -1
- data/lib/db/active_tx_log +1 -0
- data/lib/db/index/lucene-store.db +0 -0
- data/lib/db/index/lucene.log.active +0 -0
- data/lib/db/messages.log +2299 -0
- data/lib/db/neostore +0 -0
- data/lib/db/neostore.id +0 -0
- data/lib/db/neostore.nodestore.db +0 -0
- data/lib/db/neostore.nodestore.db.id +0 -0
- data/lib/db/neostore.propertystore.db +0 -0
- data/lib/db/neostore.propertystore.db.arrays +0 -0
- data/lib/db/neostore.propertystore.db.arrays.id +0 -0
- data/lib/db/neostore.propertystore.db.id +0 -0
- data/lib/db/neostore.propertystore.db.index +0 -0
- data/lib/db/neostore.propertystore.db.index.id +0 -0
- data/lib/db/neostore.propertystore.db.index.keys +0 -0
- data/lib/db/neostore.propertystore.db.index.keys.id +0 -0
- data/lib/db/neostore.propertystore.db.strings +0 -0
- data/lib/db/neostore.propertystore.db.strings.id +0 -0
- data/lib/db/neostore.relationshipstore.db +0 -0
- data/lib/db/neostore.relationshipstore.db.id +0 -0
- data/lib/db/neostore.relationshiptypestore.db +0 -0
- data/lib/db/neostore.relationshiptypestore.db.id +0 -0
- data/lib/db/neostore.relationshiptypestore.db.names +0 -0
- data/lib/db/neostore.relationshiptypestore.db.names.id +0 -0
- data/lib/db/nioneo_logical.log.active +0 -0
- data/lib/db/tm_tx_log.1 +0 -0
- data/lib/neo4j-core.rb +20 -3
- data/lib/neo4j-core/cypher/cypher.rb +1033 -0
- data/lib/neo4j-core/cypher/result_wrapper.rb +48 -0
- data/lib/neo4j-core/database.rb +4 -5
- data/lib/neo4j-core/event_handler.rb +1 -1
- data/lib/neo4j-core/hash_with_indifferent_access.rb +165 -0
- data/lib/neo4j-core/index/class_methods.rb +27 -41
- data/lib/neo4j-core/index/index.rb +3 -4
- data/lib/neo4j-core/index/index_config.rb +30 -23
- data/lib/neo4j-core/index/indexer.rb +65 -53
- data/lib/neo4j-core/index/indexer_registry.rb +2 -2
- data/lib/neo4j-core/index/lucene_query.rb +53 -42
- data/lib/neo4j-core/index/unique_factory.rb +54 -0
- data/lib/neo4j-core/node/class_methods.rb +4 -4
- data/lib/neo4j-core/node/node.rb +1 -8
- data/lib/neo4j-core/property/java.rb +59 -0
- data/lib/neo4j-core/property/property.rb +1 -3
- data/lib/neo4j-core/relationship/relationship.rb +8 -10
- data/lib/neo4j-core/rels/rels.rb +9 -4
- data/lib/neo4j-core/rels/traverser.rb +13 -27
- data/lib/neo4j-core/traversal/prune_evaluator.rb +2 -2
- data/lib/neo4j-core/traversal/traverser.rb +122 -27
- data/lib/neo4j-core/version.rb +1 -1
- data/lib/neo4j-core/wrapper/class_methods.rb +22 -0
- data/lib/neo4j-core/wrapper/wrapper.rb +20 -0
- data/lib/neo4j/algo.rb +300 -0
- data/lib/neo4j/config.rb +3 -6
- data/lib/neo4j/cypher.rb +180 -0
- data/lib/neo4j/neo4j.rb +51 -23
- data/lib/neo4j/node.rb +27 -0
- data/lib/neo4j/relationship.rb +25 -0
- data/lib/test.rb~ +27 -0
- data/neo4j-core.gemspec +2 -2
- metadata +44 -11
- data/lib/neo4j-core/type_converters/type_converters.rb +0 -287
- data/lib/neo4j-core/version.rb~ +0 -3
- 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
|
-
#
|
26
|
-
#
|
27
|
-
#
|
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
|
-
|
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
|
-
#
|
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
|
-
# @
|
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
|
-
|
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.
|
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
|
-
|
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,
|
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
|
-
|
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,
|
102
|
-
|
103
|
-
|
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,
|
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,
|
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,
|
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
|
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
|
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.
|
204
|
-
|
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 ==
|
206
|
+
when Float == field_type
|
207
207
|
Java::OrgApacheLuceneSearch::SortField::DOUBLE
|
208
|
-
when Fixnum ==
|
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,
|
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
|
224
|
-
if
|
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::
|
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::
|
232
|
+
and_query.add(range_query(key, value, value, true, true), Java::OrgApacheLuceneSearch::BooleanClause::Occur::MUST)
|
229
233
|
end
|
230
234
|
else
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
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
|
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
|
-
# @
|
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
|
data/lib/neo4j-core/node/node.rb
CHANGED
@@ -31,14 +31,7 @@ module Neo4j
|
|
31
31
|
Neo4j::Node.exist?(self)
|
32
32
|
end
|
33
33
|
|
34
|
-
#
|
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
|