neo4j 1.2.6-java → 2.0.0.alpha.3-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.
- data/CHANGELOG +30 -0
- data/CONTRIBUTORS +1 -0
- data/Gemfile +16 -4
- data/README.rdoc +25 -3
- data/bin/neo4j-jars +15 -8
- data/bin/neo4j-shell +0 -1
- data/bin/neo4j-upgrade +72 -0
- data/config/neo4j/config.yml +5 -4
- data/lib/neo4j/algo/algo.rb +0 -1
- data/lib/neo4j/batch/inserter.rb +5 -0
- data/lib/neo4j/database.rb +18 -12
- data/lib/neo4j/event_handler.rb +76 -9
- data/lib/neo4j/has_list/class_methods.rb +1 -1
- data/lib/neo4j/has_list/mapping.rb +13 -33
- data/lib/neo4j/has_n/decl_relationship_dsl.rb +17 -13
- data/lib/neo4j/has_n/mapping.rb +6 -23
- data/lib/neo4j/identity_map.rb +0 -3
- data/lib/neo4j/index/class_methods.rb +9 -3
- data/lib/neo4j/index/index.rb +2 -1
- data/lib/neo4j/index/indexer.rb +3 -2
- data/lib/neo4j/index/indexer_registry.rb +1 -1
- data/lib/neo4j/index/lucene_query.rb +52 -33
- data/lib/neo4j/neo4j.rb +19 -0
- data/lib/neo4j/node.rb +42 -36
- data/lib/neo4j/node_mixin/node_mixin.rb +9 -5
- data/lib/neo4j/paginated.rb +23 -0
- data/lib/neo4j/rails/accept_id.rb +66 -0
- data/lib/neo4j/rails/attributes.rb +14 -9
- data/lib/neo4j/rails/compositions.rb +9 -1
- data/lib/neo4j/rails/finders.rb +5 -1
- data/lib/neo4j/rails/mapping/property.rb +41 -28
- data/lib/neo4j/rails/model.rb +2 -0
- data/lib/neo4j/rails/observer.rb +61 -2
- data/lib/neo4j/rails/persistence.rb +57 -57
- data/lib/neo4j/rails/rails.rb +1 -0
- data/lib/neo4j/rails/railtie.rb +4 -1
- data/lib/neo4j/rails/rel_persistence.rb +11 -12
- data/lib/neo4j/rails/relationship.rb +9 -4
- data/lib/neo4j/rails/relationships/node_dsl.rb +15 -5
- data/lib/neo4j/rails/relationships/relationships.rb +42 -2
- data/lib/neo4j/rails/relationships/rels_dsl.rb +60 -3
- data/lib/neo4j/rails/relationships/storage.rb +43 -5
- data/lib/neo4j/rails/validations/uniqueness.rb +1 -0
- data/lib/neo4j/rails/versioning/versioning.rb +64 -9
- data/lib/neo4j/relationship.rb +79 -73
- data/lib/neo4j/rule/event_listener.rb +7 -1
- data/lib/neo4j/rule/functions/count.rb +6 -0
- data/lib/neo4j/rule/rule.rb +20 -5
- data/lib/neo4j/rule/rule_node.rb +33 -20
- data/lib/neo4j/to_java.rb +5 -0
- data/lib/neo4j/traversal/traverser.rb +38 -1
- data/lib/neo4j/type_converters/type_converters.rb +56 -5
- data/lib/neo4j/version.rb +1 -1
- data/lib/neo4j.rb +3 -49
- data/neo4j.gemspec +2 -2
- metadata +191 -216
- data/bin/neo4j-shell~ +0 -108
- data/lib/Gemfile~ +0 -3
- data/lib/config2.yml~ +0 -86
- data/lib/neo4j/jars/core/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
- data/lib/neo4j/jars/core/lucene-core-3.1.0.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-backup-1.4.1.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-graph-algo-1.4.1.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-index-1.3-1.3.M01.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-kernel-1.4.1.jar +0 -0
- data/lib/neo4j/jars/core/neo4j-lucene-index-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/log4j-1.2.16.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-com-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-ha-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-jmx-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-management-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/neo4j-shell-1.4.1.jar +0 -0
- data/lib/neo4j/jars/ha/netty-3.2.1.Final.jar +0 -0
- data/lib/neo4j/jars/ha/org.apache.servicemix.bundles.jline-0.9.94_1.jar +0 -0
- data/lib/neo4j/jars/ha/zookeeper-3.3.2.jar +0 -0
- data/lib/neo4j/paginate.rb +0 -25
- data/lib/perf.rb~ +0 -36
- data/lib/test.rb~ +0 -2
@@ -34,7 +34,7 @@ module Neo4j
|
|
34
34
|
class DeclRelationshipDsl
|
35
35
|
include Neo4j::ToJava
|
36
36
|
|
37
|
-
attr_reader :target_class, :dir, :rel_type
|
37
|
+
attr_reader :target_class, :source_class, :dir, :rel_type
|
38
38
|
|
39
39
|
def initialize(method_id, has_one, target_class)
|
40
40
|
@dir = :outgoing
|
@@ -42,6 +42,7 @@ module Neo4j
|
|
42
42
|
@has_one = has_one
|
43
43
|
@rel_type = method_id
|
44
44
|
@target_class = target_class
|
45
|
+
@source_class = target_class
|
45
46
|
end
|
46
47
|
|
47
48
|
def to_s
|
@@ -63,7 +64,7 @@ module Neo4j
|
|
63
64
|
def java_dir
|
64
65
|
dir_to_java(@dir)
|
65
66
|
end
|
66
|
-
|
67
|
+
|
67
68
|
def each_node(node, &block) #:nodoc:
|
68
69
|
node._java_node.getRelationships(java_rel_type, java_dir).each do |rel|
|
69
70
|
block.call(rel.getOtherNode(node).wrapper)
|
@@ -141,7 +142,7 @@ module Neo4j
|
|
141
142
|
if (Class === target)
|
142
143
|
# handle e.g. has_n(:friends).to(class)
|
143
144
|
@target_class = target
|
144
|
-
@rel_type = "#{@
|
145
|
+
@rel_type = "#{@source_class}##{@method_id}"
|
145
146
|
elsif (Symbol === target)
|
146
147
|
# handle e.g. has_n(:friends).to(:knows)
|
147
148
|
@rel_type = target.to_s
|
@@ -163,7 +164,7 @@ module Neo4j
|
|
163
164
|
# class FileNode
|
164
165
|
# include Neo4j::NodeMixin
|
165
166
|
# # will only traverse any incoming relationship of type files from node FileNode
|
166
|
-
# has_one(:folder).from(
|
167
|
+
# has_one(:folder).from(FolderNode, :files)
|
167
168
|
# end
|
168
169
|
#
|
169
170
|
# file = FileNode.new
|
@@ -183,7 +184,7 @@ module Neo4j
|
|
183
184
|
# end
|
184
185
|
#
|
185
186
|
# file = FileNode.new
|
186
|
-
# # create an outgoing relationship of type '
|
187
|
+
# # create an outgoing relationship of type 'files' from folder node to file
|
187
188
|
# file.folder = FolderNode.new
|
188
189
|
#
|
189
190
|
#
|
@@ -192,14 +193,9 @@ module Neo4j
|
|
192
193
|
|
193
194
|
if (args.size > 1)
|
194
195
|
# handle specified (prefixed) relationship, e.g. has_n(:known_by).from(clazz, :type)
|
195
|
-
@rel_type = "#{@target_class}##{args[1]}"
|
196
196
|
@target_class = args[0]
|
197
|
-
|
198
|
-
|
199
|
-
@relationship = other_class_dsl.relationship_class
|
200
|
-
else
|
201
|
-
Neo4j.logger.warn "Unknown outgoing relationship #{args[1]} on #{@target_class}"
|
202
|
-
end
|
197
|
+
@rel_type = "#{@target_class}##{args[1]}"
|
198
|
+
@relationship_name = args[1]
|
203
199
|
elsif (Symbol === args[0])
|
204
200
|
# handle unspecified (unprefixed) relationship, e.g. has_n(:known_by).from(:type)
|
205
201
|
@rel_type = args[0]
|
@@ -235,7 +231,15 @@ module Neo4j
|
|
235
231
|
end
|
236
232
|
|
237
233
|
def relationship_class # :nodoc:
|
238
|
-
@relationship
|
234
|
+
if !@relationship_name.nil? && @relationship.nil?
|
235
|
+
other_class_dsl = @target_class._decl_rels[@relationship_name]
|
236
|
+
if other_class_dsl
|
237
|
+
@relationship = other_class_dsl.relationship_class
|
238
|
+
else
|
239
|
+
Neo4j.logger.warn "Unknown outgoing relationship #{@relationship_name} on #{@target_class}"
|
240
|
+
end
|
241
|
+
end
|
242
|
+
@relationship
|
239
243
|
end
|
240
244
|
end
|
241
245
|
end
|
data/lib/neo4j/has_n/mapping.rb
CHANGED
@@ -7,7 +7,7 @@ module Neo4j
|
|
7
7
|
|
8
8
|
# The object created by a has_n or has_one Neo4j::NodeMixin class method which enables creating and traversal of nodes.
|
9
9
|
#
|
10
|
-
# Includes the Enumerable
|
10
|
+
# Includes the Enumerable mixin.
|
11
11
|
# The Neo4j::Mapping::ClassMethods::Relationship#has_n and Neo4j::Mapping::ClassMethods::Relationship#one
|
12
12
|
# methods returns an object of this type.
|
13
13
|
#
|
@@ -16,8 +16,6 @@ module Neo4j
|
|
16
16
|
#
|
17
17
|
class Mapping
|
18
18
|
include Enumerable
|
19
|
-
include WillPaginate::Finders::Base
|
20
|
-
|
21
19
|
include ToJava
|
22
20
|
|
23
21
|
def initialize(node, dsl) # :nodoc:
|
@@ -30,7 +28,7 @@ module Neo4j
|
|
30
28
|
end
|
31
29
|
|
32
30
|
def size
|
33
|
-
self.to_a.size
|
31
|
+
self.to_a.size # TODO: Optimise this
|
34
32
|
end
|
35
33
|
|
36
34
|
alias_method :length, :size
|
@@ -50,13 +48,13 @@ module Neo4j
|
|
50
48
|
end
|
51
49
|
|
52
50
|
# Required by the Enumerable mixin.
|
53
|
-
def each
|
54
|
-
@dsl.each_node(@node
|
51
|
+
def each
|
52
|
+
@dsl.each_node(@node) {|n| yield n} # Should use yield here as passing &block through doesn't always work (why?)
|
55
53
|
end
|
56
54
|
|
57
55
|
# returns none wrapped nodes, you may get better performance using this method
|
58
|
-
def _each
|
59
|
-
@dsl._each_node(@node
|
56
|
+
def _each
|
57
|
+
@dsl._each_node(@node) {|n| yield n}
|
60
58
|
end
|
61
59
|
|
62
60
|
# Returns an real ruby array.
|
@@ -64,21 +62,6 @@ module Neo4j
|
|
64
62
|
self.to_a
|
65
63
|
end
|
66
64
|
|
67
|
-
def wp_query(options, pager, args, &block) #:nodoc:
|
68
|
-
page = pager.current_page || 1
|
69
|
-
to = pager.per_page * page
|
70
|
-
from = to - pager.per_page
|
71
|
-
i = 0
|
72
|
-
res = []
|
73
|
-
_each do |node|
|
74
|
-
res << node.wrapper if i >= from
|
75
|
-
i += 1
|
76
|
-
break if i >= to
|
77
|
-
end
|
78
|
-
pager.replace res
|
79
|
-
pager.total_entries ||= self.size # TODO, this could be very slow to do
|
80
|
-
end
|
81
|
-
|
82
65
|
# Returns true if there are no node in this type of relationship
|
83
66
|
def empty?
|
84
67
|
first == nil
|
data/lib/neo4j/identity_map.rb
CHANGED
@@ -53,13 +53,19 @@ module Neo4j
|
|
53
53
|
#
|
54
54
|
# Person.index_names[:fulltext] => 'my_location'
|
55
55
|
# Person.index_names[:exact] => 'Foo_Person-exact' # default Location
|
56
|
-
#
|
57
|
-
#
|
56
|
+
#
|
57
|
+
# The index can be prefixed, see Neo4j#threadlocal_ref_node= and multi dendency.
|
58
58
|
#
|
59
59
|
# :singleton-method: index_names
|
60
60
|
|
61
61
|
|
62
|
-
|
62
|
+
##
|
63
|
+
# Returns a hash of which indexes has been defined and the type of index (:exact or :fulltext)
|
64
|
+
#
|
65
|
+
# :singleton-method: index_types
|
66
|
+
|
67
|
+
|
68
|
+
def_delegators :@_indexer, :index, :find, :index?, :index_type?, :delete_index_type, :rm_field_type, :add_index, :rm_index, :index_type_for, :index_names, :index_types
|
63
69
|
|
64
70
|
# Sets which indexer should be used for the given node class.
|
65
71
|
# You can share an indexer between several different classes.
|
data/lib/neo4j/index/index.rb
CHANGED
@@ -19,7 +19,8 @@ module Neo4j
|
|
19
19
|
# Neo4j::Index::ClassMethods::index
|
20
20
|
#
|
21
21
|
def add_index(field, value=self[field])
|
22
|
-
|
22
|
+
converted_value = Neo4j::TypeConverters.convert(value, field, self.class)
|
23
|
+
self.class.add_index(wrapped_entity, field.to_s, converted_value)
|
23
24
|
end
|
24
25
|
|
25
26
|
# Removes an index on the given property.
|
data/lib/neo4j/index/indexer.rb
CHANGED
@@ -2,6 +2,7 @@ module Neo4j
|
|
2
2
|
module Index
|
3
3
|
class Indexer
|
4
4
|
attr_reader :indexer_for, :field_types, :via_relationships, :entity_type, :parent_indexers, :via_relationships
|
5
|
+
alias_method :index_types, :field_types # public method accessible from node.index_types
|
5
6
|
|
6
7
|
def initialize(clazz, type) #:nodoc:
|
7
8
|
# part of the unique name of the index
|
@@ -155,7 +156,7 @@ module Neo4j
|
|
155
156
|
end
|
156
157
|
|
157
158
|
def update_single_index_on(node, field, old_val, new_val) #:nodoc:
|
158
|
-
if @field_types.
|
159
|
+
if @field_types.has_key?(field)
|
159
160
|
rm_index(node, field, old_val) if old_val
|
160
161
|
add_index(node, field, new_val) if new_val
|
161
162
|
end
|
@@ -322,7 +323,7 @@ module Neo4j
|
|
322
323
|
def index_names
|
323
324
|
@index_names ||= Hash.new do |hash, index_type|
|
324
325
|
default_filename = index_prefix + @indexer_for.to_s.gsub('::', '_')
|
325
|
-
hash.fetch(index_type) {"#{default_filename}
|
326
|
+
hash.fetch(index_type) {"#{default_filename}_#{index_type}"}
|
326
327
|
end
|
327
328
|
end
|
328
329
|
|
@@ -10,7 +10,7 @@ module Neo4j
|
|
10
10
|
def create_for(this_clazz, using_other_clazz, type)
|
11
11
|
@@indexers ||= {}
|
12
12
|
index = Indexer.new(this_clazz, type)
|
13
|
-
index.inherit_fields_from(@@indexers[using_other_clazz.to_s])
|
13
|
+
index.inherit_fields_from(@@indexers[using_other_clazz.to_s]) if @@indexers[using_other_clazz.to_s]
|
14
14
|
@@indexers[this_clazz.to_s] = index
|
15
15
|
end
|
16
16
|
|
@@ -37,8 +37,7 @@ module Neo4j
|
|
37
37
|
#
|
38
38
|
class LuceneQuery
|
39
39
|
include Enumerable
|
40
|
-
|
41
|
-
attr_accessor :left_and_query, :left_or_query
|
40
|
+
attr_accessor :left_and_query, :left_or_query, :right_not_query
|
42
41
|
|
43
42
|
def initialize(index, decl_props, query, params={})
|
44
43
|
@index = index
|
@@ -52,30 +51,9 @@ module Neo4j
|
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
55
|
-
|
56
|
-
@params[:page] = pager.current_page
|
57
|
-
@params[:per_page] = pager.per_page
|
58
|
-
pager.replace [*self]
|
59
|
-
pager.total_entries = size
|
60
|
-
end
|
61
|
-
|
62
|
-
# Since we include the Ruby Enumerable mixin we need this method.
|
54
|
+
# Implements the Ruby +Enumerable+ interface
|
63
55
|
def each
|
64
|
-
|
65
|
-
# paginate the result, used by the will_paginate gem
|
66
|
-
page = @params[:page] || 1
|
67
|
-
per_page = @params[:per_page]
|
68
|
-
to = per_page * page
|
69
|
-
from = to - per_page
|
70
|
-
i = 0
|
71
|
-
hits.each do |node|
|
72
|
-
yield node.wrapper if i >= from
|
73
|
-
i += 1
|
74
|
-
break if i >= to
|
75
|
-
end
|
76
|
-
else
|
77
|
-
hits.each { |n| yield n.wrapper }
|
78
|
-
end
|
56
|
+
hits.each { |x| yield x.wrapper }
|
79
57
|
end
|
80
58
|
|
81
59
|
# Close hits
|
@@ -156,9 +134,33 @@ module Neo4j
|
|
156
134
|
# Person.find(:name=>'kalle').and(:age => 3)
|
157
135
|
#
|
158
136
|
def and(query2)
|
159
|
-
|
160
|
-
|
161
|
-
|
137
|
+
LuceneQuery.new(@index, @decl_props, query2).tap { |new_query| new_query.left_and_query = self }
|
138
|
+
end
|
139
|
+
|
140
|
+
# Create an OR lucene query.
|
141
|
+
#
|
142
|
+
# ==== Parameters
|
143
|
+
# query2 :: the query that should be OR together
|
144
|
+
#
|
145
|
+
# ==== Example
|
146
|
+
#
|
147
|
+
# Person.find(:name=>'kalle').or(:age => 3)
|
148
|
+
#
|
149
|
+
def or(query2)
|
150
|
+
LuceneQuery.new(@index, @decl_props, query2).tap { |new_query| new_query.left_or_query = self }
|
151
|
+
end
|
152
|
+
|
153
|
+
# Create a NOT lucene query.
|
154
|
+
#
|
155
|
+
# ==== Parameters
|
156
|
+
# query2 :: the query that should exclude matching results
|
157
|
+
#
|
158
|
+
# ==== Example
|
159
|
+
#
|
160
|
+
# Person.find(:age => 3).not(:name=>'kalle')
|
161
|
+
#
|
162
|
+
def not(query2)
|
163
|
+
LuceneQuery.new(@index, @decl_props, query2).tap { |new_query| new_query.right_not_query = self }
|
162
164
|
end
|
163
165
|
|
164
166
|
|
@@ -175,11 +177,26 @@ module Neo4j
|
|
175
177
|
end
|
176
178
|
|
177
179
|
def build_and_query(query) #:nodoc:
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
180
|
+
build_composite_query(@left_and_query.build_query, query, org.apache.lucene.search.BooleanClause::Occur::MUST)
|
181
|
+
end
|
182
|
+
|
183
|
+
def build_or_query(query) #:nodoc:
|
184
|
+
build_composite_query(@left_or_query.build_query, query, org.apache.lucene.search.BooleanClause::Occur::SHOULD)
|
185
|
+
end
|
186
|
+
|
187
|
+
def build_not_query(query) #:nodoc:
|
188
|
+
right_query = @right_not_query.build_query
|
189
|
+
composite_query = org.apache.lucene.search.BooleanQuery.new
|
190
|
+
composite_query.add(query, org.apache.lucene.search.BooleanClause::Occur::MUST_NOT)
|
191
|
+
composite_query.add(right_query, org.apache.lucene.search.BooleanClause::Occur::MUST)
|
192
|
+
composite_query
|
193
|
+
end
|
194
|
+
|
195
|
+
def build_composite_query(left_query, right_query, opeartor) #:nodoc:
|
196
|
+
composite_query = org.apache.lucene.search.BooleanQuery.new
|
197
|
+
composite_query.add(left_query, opeartor)
|
198
|
+
composite_query.add(right_query, opeartor)
|
199
|
+
composite_query
|
183
200
|
end
|
184
201
|
|
185
202
|
def build_sort_query(query) #:nodoc:
|
@@ -224,6 +241,8 @@ module Neo4j
|
|
224
241
|
query = @query
|
225
242
|
query = build_hash_query(query) if Hash === query
|
226
243
|
query = build_and_query(query) if @left_and_query
|
244
|
+
query = build_or_query(query) if @left_or_query
|
245
|
+
query = build_not_query(query) if @right_not_query
|
227
246
|
query = build_sort_query(query) if @order
|
228
247
|
query
|
229
248
|
end
|
data/lib/neo4j/neo4j.rb
CHANGED
@@ -13,6 +13,9 @@ require 'neo4j/database'
|
|
13
13
|
#
|
14
14
|
module Neo4j
|
15
15
|
|
16
|
+
# The version of the Neo4j jar files
|
17
|
+
NEO_VERSION = Neo4j::Community::VERSION
|
18
|
+
|
16
19
|
class << self
|
17
20
|
# Start Neo4j using the default database.
|
18
21
|
# This is usally not required since the database will be started automatically when it is used.
|
@@ -71,6 +74,22 @@ module Neo4j
|
|
71
74
|
Neo4j::Config
|
72
75
|
end
|
73
76
|
|
77
|
+
# Executes a Cypher Query
|
78
|
+
# Check the neo4j http://docs.neo4j.org/chunked/milestone/cypher-query-lang.html
|
79
|
+
# Returns an enumerable of hash values.
|
80
|
+
#
|
81
|
+
# === Usage
|
82
|
+
#
|
83
|
+
# q = Neo4j.query("START n=node({node}) RETURN n", 'node' => @node.neo_id)
|
84
|
+
# q.first['n'] #=> the @node
|
85
|
+
# q.columns.first => 'n'
|
86
|
+
#
|
87
|
+
def query(query, params = {})
|
88
|
+
engine = org.neo4j.cypher.javacompat.ExecutionEngine.new(db)
|
89
|
+
engine.execute(query, params)
|
90
|
+
end
|
91
|
+
|
92
|
+
|
74
93
|
# Returns the logger used by neo4j.
|
75
94
|
# If not specified (with Neo4j.logger=) it will use the standard Ruby logger.
|
76
95
|
# You can change standard logger threshold by configuration :logger_level.
|
data/lib/neo4j/node.rb
CHANGED
@@ -7,42 +7,6 @@ require 'neo4j/equal'
|
|
7
7
|
require 'neo4j/load'
|
8
8
|
|
9
9
|
module Neo4j
|
10
|
-
|
11
|
-
org.neo4j.kernel.impl.core.NodeProxy.class_eval do
|
12
|
-
include Neo4j::Property
|
13
|
-
include Neo4j::Rels
|
14
|
-
include Neo4j::Traversal
|
15
|
-
include Neo4j::Equal
|
16
|
-
include Neo4j::Index
|
17
|
-
|
18
|
-
def del #:nodoc:
|
19
|
-
rels.each {|r| r.del}
|
20
|
-
delete
|
21
|
-
nil
|
22
|
-
end
|
23
|
-
|
24
|
-
def exist? #:nodoc:
|
25
|
-
Neo4j::Node.exist?(self)
|
26
|
-
end
|
27
|
-
|
28
|
-
def wrapped_entity #:nodoc:
|
29
|
-
self
|
30
|
-
end
|
31
|
-
|
32
|
-
def wrapper #:nodoc:
|
33
|
-
self.class.wrapper(self)
|
34
|
-
end
|
35
|
-
|
36
|
-
def _java_node #:nodoc:
|
37
|
-
self
|
38
|
-
end
|
39
|
-
|
40
|
-
def class #:nodoc:
|
41
|
-
Neo4j::Node
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
10
|
# A node in the graph with properties and relationships to other entities.
|
47
11
|
# Along with relationships, nodes are the core building blocks of the Neo4j data representation model.
|
48
12
|
# Node has three major groups of operations: operations that deal with relationships, operations that deal with properties and operations that traverse the node space.
|
@@ -259,6 +223,48 @@ module Neo4j
|
|
259
223
|
nil
|
260
224
|
end
|
261
225
|
|
226
|
+
def extend_java_class(java_clazz) #:nodoc:
|
227
|
+
java_clazz.class_eval do
|
228
|
+
include Neo4j::Property
|
229
|
+
include Neo4j::Rels
|
230
|
+
include Neo4j::Traversal
|
231
|
+
include Neo4j::Equal
|
232
|
+
include Neo4j::Index
|
233
|
+
|
234
|
+
def del #:nodoc:
|
235
|
+
rels.each { |r| r.del }
|
236
|
+
delete
|
237
|
+
nil
|
238
|
+
end
|
239
|
+
|
240
|
+
def exist? #:nodoc:
|
241
|
+
Neo4j::Node.exist?(self)
|
242
|
+
end
|
243
|
+
|
244
|
+
def wrapped_entity #:nodoc:
|
245
|
+
self
|
246
|
+
end
|
247
|
+
|
248
|
+
def wrapper #:nodoc:
|
249
|
+
self.class.wrapper(self)
|
250
|
+
end
|
251
|
+
|
252
|
+
def _java_node #:nodoc:
|
253
|
+
self
|
254
|
+
end
|
255
|
+
|
256
|
+
def class #:nodoc:
|
257
|
+
Neo4j::Node
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
262
261
|
end
|
263
262
|
end
|
263
|
+
|
264
|
+
# org.neo4j.kernel.HighlyAvailableGraphDatabase$LookupNode
|
265
|
+
#
|
266
|
+
Neo4j::Node.extend_java_class(org.neo4j.kernel.impl.core.NodeProxy)
|
267
|
+
|
268
|
+
|
269
|
+
|
264
270
|
end
|
@@ -36,8 +36,6 @@ module Neo4j
|
|
36
36
|
# * Neo4j::Index::ClassMethods
|
37
37
|
# * Neo4j::HasList::ClassMethods
|
38
38
|
#
|
39
|
-
# This class also includes the class mixin WillPaginate::Finders::Base, see http://github.com/mislav/will_paginate/wiki
|
40
|
-
#
|
41
39
|
module NodeMixin
|
42
40
|
include Neo4j::Index
|
43
41
|
|
@@ -80,7 +78,7 @@ module Neo4j
|
|
80
78
|
def _java_entity
|
81
79
|
@_java_node
|
82
80
|
end
|
83
|
-
|
81
|
+
|
84
82
|
# Trigger rules.
|
85
83
|
# You don't normally need to call this method (except in Migration) since
|
86
84
|
# it will be triggered automatically by the Neo4j::Rule::Rule
|
@@ -99,6 +97,13 @@ module Neo4j
|
|
99
97
|
self
|
100
98
|
end
|
101
99
|
|
100
|
+
def pagination_source(*a)
|
101
|
+
binding.pry
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.pagination_source(*a)
|
105
|
+
binding.pry
|
106
|
+
end
|
102
107
|
|
103
108
|
def self.included(c) # :nodoc:
|
104
109
|
c.instance_eval do
|
@@ -119,7 +124,6 @@ module Neo4j
|
|
119
124
|
c.extend Neo4j::Rule::ClassMethods
|
120
125
|
c.extend Neo4j::HasList::ClassMethods
|
121
126
|
c.extend Neo4j::Index::ClassMethods
|
122
|
-
c.extend WillPaginate::Finders::Base
|
123
127
|
|
124
128
|
def c.inherited(subclass)
|
125
129
|
# inherit the index properties
|
@@ -131,7 +135,7 @@ module Neo4j
|
|
131
135
|
super
|
132
136
|
end
|
133
137
|
|
134
|
-
c.node_indexer c
|
138
|
+
c.node_indexer c unless c == Neo4j::Rails::Model
|
135
139
|
end
|
136
140
|
end
|
137
141
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Neo4j
|
2
|
+
|
3
|
+
# The class provides the pagination based on the given source.
|
4
|
+
# The source must be an Enumerable implementing methods drop, first and count (or size).
|
5
|
+
# This can be used to paginage any Enumerable collection and
|
6
|
+
# provides the integration point for other gems, like will_paginate and kaminari.
|
7
|
+
class Paginated
|
8
|
+
include Enumerable
|
9
|
+
attr_reader :items, :total, :current_page
|
10
|
+
|
11
|
+
def initialize(items, total, current_page)
|
12
|
+
@items, @total, @current_page = items, total, current_page
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.create_from(source, page, per_page)
|
16
|
+
partial = source.drop((page-1) * per_page).first(per_page)
|
17
|
+
Paginated.new(partial, source.count, page)
|
18
|
+
end
|
19
|
+
|
20
|
+
delegate :each, :to => :items
|
21
|
+
delegate :size, :[], :to => :items
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Neo4j::Rails
|
2
|
+
# Allows accepting id for association objects. For example
|
3
|
+
# class Book < Neo4j::Model
|
4
|
+
# has_one(:author).to(Author)
|
5
|
+
# accepts_id_for :author
|
6
|
+
# end
|
7
|
+
#
|
8
|
+
# This would add a author_id getter and setter on Book. You could use
|
9
|
+
# book = Book.new(:name => 'Graph DBs', :author_id => 11)
|
10
|
+
# book.author_id # 11
|
11
|
+
# book.author_id = 13
|
12
|
+
# TODO: Support for has_n associations
|
13
|
+
module AcceptId
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
# Adds association_id getter and setter for one or more has_one associations
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# class Book < Neo4j::Model
|
21
|
+
# has_one(:author).to(Author)
|
22
|
+
# has_one(:publisher).to(Publisher)
|
23
|
+
# accepts_id_for :author, :publisher
|
24
|
+
# end
|
25
|
+
def accepts_id_for(*association_names)
|
26
|
+
association_names.each do |association_name|
|
27
|
+
define_association_id_getter(association_name)
|
28
|
+
define_association_id_setter(association_name)
|
29
|
+
accepts_id_associations << association_name
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Check if model accepsts id for its association
|
34
|
+
# @example
|
35
|
+
# Book.accepts_id_for?(:author) => true
|
36
|
+
# Book.accepts_id_for?(:genre) => false
|
37
|
+
def accepts_id_for?(association_name)
|
38
|
+
accepts_id_associations.include?(association_name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def accepts_id_associations #nodoc
|
42
|
+
@accepts_id_associations ||= []
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
def define_association_id_getter(association_name)
|
47
|
+
class_eval %Q{
|
48
|
+
def #{association_name}_id
|
49
|
+
association_object = self.#{association_name}
|
50
|
+
association_object.present? ? association_object.id : nil
|
51
|
+
end
|
52
|
+
}, __FILE__, __LINE__
|
53
|
+
end
|
54
|
+
|
55
|
+
def define_association_id_setter(association_name)
|
56
|
+
class_eval %Q{
|
57
|
+
def #{association_name}_id=(id)
|
58
|
+
relation_target_class = self.class._decl_rels[:#{association_name}].target_class
|
59
|
+
association_class = relation_target_class <= self.class ? Neo4j::Model : relation_target_class
|
60
|
+
self.#{association_name} = id.present? ? association_class.find(id) : nil
|
61
|
+
end
|
62
|
+
}, __FILE__, __LINE__
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -38,7 +38,7 @@ module Neo4j
|
|
38
38
|
key_s = key.to_s
|
39
39
|
if !@properties.has_key?(key_s) || @properties[key_s] != value
|
40
40
|
attribute_will_change!(key_s)
|
41
|
-
@properties[key_s] = value
|
41
|
+
@properties[key_s] = value.nil? ? attribute_defaults[key_s] : value
|
42
42
|
end
|
43
43
|
value
|
44
44
|
end
|
@@ -98,16 +98,17 @@ module Neo4j
|
|
98
98
|
send(name + "=", nil)
|
99
99
|
else
|
100
100
|
|
101
|
-
|
101
|
+
#TODO: Consider extracting hardcoded assignments into "Binders"
|
102
|
+
value = if Neo4j::TypeConverters::TimeConverter.convert?(decl_type)
|
102
103
|
instantiate_time_object(name, values)
|
103
|
-
elsif
|
104
|
+
elsif Neo4j::TypeConverters::DateConverter.convert?(decl_type)
|
104
105
|
begin
|
105
106
|
values = values_with_empty_parameters.collect do |v| v.nil? ? 1 : v end
|
106
107
|
Date.new(*values)
|
107
108
|
rescue ArgumentError => ex # if Date.new raises an exception on an invalid date
|
108
109
|
instantiate_time_object(name, values).to_date # we instantiate Time object and convert it back to a date thus using Time's logic in handling invalid dates
|
109
110
|
end
|
110
|
-
elsif
|
111
|
+
elsif Neo4j::TypeConverters::DateTimeConverter.convert?(decl_type)
|
111
112
|
DateTime.new(*values)
|
112
113
|
else
|
113
114
|
raise "Unknown type #{decl_type}"
|
@@ -201,8 +202,8 @@ module Neo4j
|
|
201
202
|
# Known properties are either in the @properties, the declared
|
202
203
|
# properties or the property keys for the persisted node
|
203
204
|
def property?(name)
|
204
|
-
@properties.
|
205
|
-
self.class._decl_props.
|
205
|
+
@properties.has_key?(name) ||
|
206
|
+
self.class._decl_props.has_key?(name) ||
|
206
207
|
begin
|
207
208
|
persisted? && super
|
208
209
|
rescue org.neo4j.graphdb.NotFoundException
|
@@ -216,9 +217,13 @@ module Neo4j
|
|
216
217
|
def attribute?(name)
|
217
218
|
name[0] != ?_ && property?(name)
|
218
219
|
end
|
219
|
-
|
220
|
+
|
220
221
|
def _classname
|
221
|
-
self
|
222
|
+
self.class.to_s
|
223
|
+
end
|
224
|
+
|
225
|
+
def _classname=(value)
|
226
|
+
write_local_property_without_type_conversion("_classname",value)
|
222
227
|
end
|
223
228
|
|
224
229
|
# To get ActiveModel::Dirty to work, we need to be able to call undeclared
|
@@ -248,7 +253,7 @@ module Neo4j
|
|
248
253
|
|
249
254
|
# Wrap the setter in a conversion from Ruby to Java
|
250
255
|
def write_local_property_with_type_conversion(property, value)
|
251
|
-
|
256
|
+
@properties_before_type_cast[property.to_sym]=value if self.class._decl_props.has_key? property.to_sym
|
252
257
|
write_local_property_without_type_conversion(property, Neo4j::TypeConverters.to_java(self.class, property, value))
|
253
258
|
end
|
254
259
|
end
|