neo4j 1.0.0.beta.20 → 3.0.0.alpha.2
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.
- checksums.yaml +7 -0
- data/CHANGELOG +243 -0
- data/CONTRIBUTORS +12 -0
- data/Gemfile +10 -11
- data/README.md +23 -0
- data/bin/neo4j-jars +33 -0
- data/config/locales/en.yml +5 -0
- data/config/neo4j/config.yml +98 -0
- data/lib/neo4j.rb +28 -68
- data/lib/neo4j/active_node.rb +60 -0
- data/lib/neo4j/active_node/callbacks.rb +41 -0
- data/lib/neo4j/active_node/has_n.rb +138 -0
- data/lib/neo4j/active_node/has_n/decl_rel.rb +236 -0
- data/lib/neo4j/active_node/has_n/nodes.rb +82 -0
- data/lib/neo4j/active_node/identity.rb +28 -0
- data/lib/neo4j/active_node/initialize.rb +24 -0
- data/lib/neo4j/active_node/labels.rb +142 -0
- data/lib/neo4j/active_node/persistence.rb +193 -0
- data/lib/neo4j/active_node/property.rb +41 -0
- data/lib/neo4j/active_node/rels.rb +11 -0
- data/lib/neo4j/active_node/validations.rb +51 -0
- data/lib/neo4j/railtie.rb +40 -0
- data/lib/neo4j/version.rb +1 -1
- data/lib/neo4j/wrapper.rb +25 -0
- data/neo4j.gemspec +25 -15
- metadata +136 -149
- data/README.rdoc +0 -135
- data/lib/generators/neo4j.rb +0 -65
- data/lib/generators/neo4j/model/model_generator.rb +0 -39
- data/lib/generators/neo4j/model/templates/model.erb +0 -7
- data/lib/neo4j/config.rb +0 -153
- data/lib/neo4j/database.rb +0 -56
- data/lib/neo4j/equal.rb +0 -21
- data/lib/neo4j/event_handler.rb +0 -116
- data/lib/neo4j/index/class_methods.rb +0 -62
- data/lib/neo4j/index/index.rb +0 -33
- data/lib/neo4j/index/indexer.rb +0 -312
- data/lib/neo4j/index/indexer_registry.rb +0 -68
- data/lib/neo4j/index/lucene_query.rb +0 -191
- data/lib/neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
- data/lib/neo4j/jars/lucene-core-3.0.2.jar +0 -0
- data/lib/neo4j/jars/neo4j-index-1.2-1.2.M03.jar +0 -0
- data/lib/neo4j/jars/neo4j-kernel-1.2-1.2.M03.jar +0 -0
- data/lib/neo4j/jars/neo4j-lucene-index-0.2-1.2.M03.jar +0 -0
- data/lib/neo4j/load.rb +0 -21
- data/lib/neo4j/mapping/class_methods/init_node.rb +0 -50
- data/lib/neo4j/mapping/class_methods/init_rel.rb +0 -35
- data/lib/neo4j/mapping/class_methods/property.rb +0 -80
- data/lib/neo4j/mapping/class_methods/relationship.rb +0 -90
- data/lib/neo4j/mapping/class_methods/root.rb +0 -31
- data/lib/neo4j/mapping/class_methods/rule.rb +0 -295
- data/lib/neo4j/mapping/decl_relationship_dsl.rb +0 -214
- data/lib/neo4j/mapping/has_n.rb +0 -83
- data/lib/neo4j/mapping/node_mixin.rb +0 -97
- data/lib/neo4j/mapping/relationship_mixin.rb +0 -117
- data/lib/neo4j/model.rb +0 -4
- data/lib/neo4j/neo4j.rb +0 -95
- data/lib/neo4j/node.rb +0 -131
- data/lib/neo4j/node_mixin.rb +0 -4
- data/lib/neo4j/node_relationship.rb +0 -149
- data/lib/neo4j/node_traverser.rb +0 -157
- data/lib/neo4j/property.rb +0 -111
- data/lib/neo4j/rails/finders.rb +0 -121
- data/lib/neo4j/rails/lucene_connection_closer.rb +0 -19
- data/lib/neo4j/rails/mapping/property.rb +0 -35
- data/lib/neo4j/rails/model.rb +0 -324
- data/lib/neo4j/rails/railtie.rb +0 -16
- data/lib/neo4j/rails/transaction.rb +0 -67
- data/lib/neo4j/rails/tx_methods.rb +0 -15
- data/lib/neo4j/rails/validations/non_nil.rb +0 -11
- data/lib/neo4j/rails/validations/uniqueness.rb +0 -31
- data/lib/neo4j/rails/value.rb +0 -124
- data/lib/neo4j/rails/value_properties.rb +0 -29
- data/lib/neo4j/relationship.rb +0 -169
- data/lib/neo4j/relationship_mixin.rb +0 -4
- data/lib/neo4j/relationship_traverser.rb +0 -92
- data/lib/neo4j/to_java.rb +0 -31
- data/lib/neo4j/transaction.rb +0 -68
- data/lib/neo4j/type_converters.rb +0 -98
@@ -1,90 +0,0 @@
|
|
1
|
-
module Neo4j::Mapping
|
2
|
-
module ClassMethods
|
3
|
-
|
4
|
-
module Relationship
|
5
|
-
include Neo4j::ToJava
|
6
|
-
|
7
|
-
# Specifies a relationship between two node classes.
|
8
|
-
# Generates assignment and accessor methods for the given relationship.
|
9
|
-
# Both incoming and outgoing relationships can be declared, see Neo4j::Mapping::DeclRelationshipDsl
|
10
|
-
#
|
11
|
-
# ==== Example
|
12
|
-
#
|
13
|
-
# class FolderNode
|
14
|
-
# include Ne4j::NodeMixin
|
15
|
-
# has_n(:files)
|
16
|
-
# end
|
17
|
-
#
|
18
|
-
# folder = FolderNode.new
|
19
|
-
# folder.files << Neo4j::Node.new << Neo4j::Node.new
|
20
|
-
# folder.files.inject {...}
|
21
|
-
#
|
22
|
-
# ==== Returns
|
23
|
-
#
|
24
|
-
# Neo4j::Mapping::DeclRelationshipDsl
|
25
|
-
#
|
26
|
-
def has_n(rel_type, params = {})
|
27
|
-
clazz = self
|
28
|
-
module_eval(%Q{
|
29
|
-
def #{rel_type}
|
30
|
-
dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
|
31
|
-
Neo4j::Mapping::HasN.new(self, dsl)
|
32
|
-
end}, __FILE__, __LINE__)
|
33
|
-
|
34
|
-
module_eval(%Q{
|
35
|
-
def #{rel_type}_rels
|
36
|
-
dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
|
37
|
-
dsl.all_relationships(self)
|
38
|
-
end}, __FILE__, __LINE__)
|
39
|
-
|
40
|
-
_decl_rels[rel_type.to_sym] = Neo4j::Mapping::DeclRelationshipDsl.new(rel_type, false, clazz, params)
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
# Specifies a relationship between two node classes.
|
45
|
-
# Generates assignment and accessor methods for the given relationship
|
46
|
-
# Old relationship is deleted when a new relationship is assigned.
|
47
|
-
# Both incoming and outgoing relationships can be declared, see Neo4j::Mapping::DeclRelationshipDsl
|
48
|
-
#
|
49
|
-
# ==== Example
|
50
|
-
#
|
51
|
-
# class FileNode
|
52
|
-
# include Ne4j::NodeMixin
|
53
|
-
# has_one(:folder)
|
54
|
-
# end
|
55
|
-
#
|
56
|
-
# file = FileNode.new
|
57
|
-
# file.folder = Neo4j::Node.new
|
58
|
-
# file.folder # => the node above
|
59
|
-
# file.folder_rel # => the relationship object between those nodes
|
60
|
-
#
|
61
|
-
# ==== Returns
|
62
|
-
#
|
63
|
-
# Neo4j::Mapping::DeclRelationshipDsl
|
64
|
-
#
|
65
|
-
def has_one(rel_type, params = {})
|
66
|
-
clazz = self
|
67
|
-
module_eval(%Q{def #{rel_type}=(value)
|
68
|
-
dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
|
69
|
-
rel = dsl.single_relationship(self)
|
70
|
-
rel.del unless rel.nil?
|
71
|
-
dsl.create_relationship_to(self, value) if value
|
72
|
-
end}, __FILE__, __LINE__)
|
73
|
-
|
74
|
-
module_eval(%Q{def #{rel_type}
|
75
|
-
dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
|
76
|
-
dsl.single_node(self)
|
77
|
-
end}, __FILE__, __LINE__)
|
78
|
-
|
79
|
-
module_eval(%Q{
|
80
|
-
def #{rel_type}_rel
|
81
|
-
dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
|
82
|
-
dsl.single_relationship(self)
|
83
|
-
end}, __FILE__, __LINE__)
|
84
|
-
|
85
|
-
_decl_rels[rel_type.to_sym] = Neo4j::Mapping::DeclRelationshipDsl.new(rel_type, true, clazz, params)
|
86
|
-
end
|
87
|
-
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module Neo4j::Mapping
|
2
|
-
module ClassMethods
|
3
|
-
# Used to hold information about which relationships and properties has been declared.
|
4
|
-
module Root
|
5
|
-
#attr_reader :_decl_rels, :_decl_props
|
6
|
-
|
7
|
-
def root_class(clazz)
|
8
|
-
@@_all_decl_rels ||= {}
|
9
|
-
@@_all_decl_props ||= {}
|
10
|
-
@@_all_decl_rels[clazz] ||= {}
|
11
|
-
@@_all_decl_props[clazz] ||= {}
|
12
|
-
@_decl_rels = @@_all_decl_rels[clazz]
|
13
|
-
@_decl_props = @@_all_decl_props[clazz]
|
14
|
-
end
|
15
|
-
|
16
|
-
|
17
|
-
# a hash of all relationships which has been declared with a has_n or has_one using Neo4j::Mapping::ClassMethods::Relationship
|
18
|
-
def _decl_rels
|
19
|
-
@@_all_decl_rels[self] ||= {}
|
20
|
-
@_decl_props = @@_all_decl_rels[self]
|
21
|
-
end
|
22
|
-
|
23
|
-
# a hash of all properties which has been declared with <tt>property</tt> using the Neo4j::Mapping::ClassMethods::Property
|
24
|
-
def _decl_props
|
25
|
-
@@_all_decl_props[self] ||= {}
|
26
|
-
@_decl_props = @@_all_decl_props[self]
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,295 +0,0 @@
|
|
1
|
-
module Neo4j::Mapping
|
2
|
-
module ClassMethods
|
3
|
-
# Holds all defined rules and trigger them when an event is received.
|
4
|
-
#
|
5
|
-
# See Rule
|
6
|
-
#
|
7
|
-
class Rules
|
8
|
-
class << self
|
9
|
-
def add(clazz, field, props, &block)
|
10
|
-
clazz = clazz.to_s
|
11
|
-
@rules ||= {}
|
12
|
-
# was there no ruls for this class AND is neo4j running ?
|
13
|
-
if !@rules.include?(clazz) && Neo4j.running?
|
14
|
-
# maybe Neo4j was started first and the rules was added later. Create rule nodes now
|
15
|
-
create_rule_node_for(clazz)
|
16
|
-
end
|
17
|
-
@rules[clazz] ||= {}
|
18
|
-
filter = block.nil? ? Proc.new { |*| true } : block
|
19
|
-
@rules[clazz][field] = filter
|
20
|
-
@triggers ||= {}
|
21
|
-
@triggers[clazz] ||= {}
|
22
|
-
trigger = props[:trigger].nil? ? [] : props[:trigger]
|
23
|
-
@triggers[clazz][field] = trigger.respond_to?(:each) ? trigger : [trigger]
|
24
|
-
end
|
25
|
-
|
26
|
-
def inherit(parent_class, subclass)
|
27
|
-
# copy all the rules
|
28
|
-
@rules[parent_class.to_s].each_pair do |field, filter|
|
29
|
-
subclass.rule field, &filter
|
30
|
-
end if @rules[parent_class.to_s]
|
31
|
-
end
|
32
|
-
|
33
|
-
def trigger_other_rules(node)
|
34
|
-
clazz = node[:_classname]
|
35
|
-
@rules[clazz].keys.each do |field|
|
36
|
-
rel_types = @triggers[clazz][field]
|
37
|
-
rel_types.each do |rel_type|
|
38
|
-
node.incoming(rel_type).each { |n| n.trigger_rules }
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def fields_for(clazz)
|
44
|
-
clazz = clazz.to_s
|
45
|
-
return [] if @rules.nil? || @rules[clazz].nil?
|
46
|
-
@rules[clazz].keys
|
47
|
-
end
|
48
|
-
|
49
|
-
def delete(clazz)
|
50
|
-
clazz = clazz.to_s
|
51
|
-
# delete the rule node if found
|
52
|
-
if Neo4j.ref_node.rel?(clazz)
|
53
|
-
Neo4j.ref_node.outgoing(clazz).each { |n| n.del }
|
54
|
-
end
|
55
|
-
@rules.delete(clazz) if @rules
|
56
|
-
end
|
57
|
-
|
58
|
-
def on_neo4j_started(*)
|
59
|
-
@rules.each_key { |clazz| create_rule_node_for(clazz) } if @rules
|
60
|
-
end
|
61
|
-
|
62
|
-
def create_rule_node_for(clazz)
|
63
|
-
if !Neo4j.ref_node.rel?(clazz)
|
64
|
-
Neo4j::Transaction.run do
|
65
|
-
node = Neo4j::Node.new
|
66
|
-
Neo4j.ref_node.outgoing(clazz) << node
|
67
|
-
node
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def trigger?(node)
|
73
|
-
@rules && node.property?(:_classname) && @rules.include?(node[:_classname])
|
74
|
-
end
|
75
|
-
|
76
|
-
def rule_for(clazz)
|
77
|
-
if Neo4j.ref_node.rel?(clazz)
|
78
|
-
Neo4j.ref_node._rel(:outgoing, clazz)._end_node
|
79
|
-
else
|
80
|
-
# this should be called if the rule node gets deleted
|
81
|
-
create_rule_node_for(clazz)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
def on_relationship_created(rel, *)
|
87
|
-
trigger_start_node = trigger?(rel._start_node)
|
88
|
-
trigger_end_node = trigger?(rel._end_node)
|
89
|
-
# end or start node must be triggered by this event
|
90
|
-
return unless trigger_start_node || trigger_end_node
|
91
|
-
on_property_changed(trigger_start_node ? rel._start_node : rel._end_node)
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
|
-
def on_property_changed(node, *)
|
96
|
-
trigger_rules(node) if trigger?(node)
|
97
|
-
end
|
98
|
-
|
99
|
-
def trigger_rules(node)
|
100
|
-
trigger_rules_for_class(node, node[:_classname])
|
101
|
-
trigger_other_rules(node)
|
102
|
-
end
|
103
|
-
|
104
|
-
def trigger_rules_for_class(node, clazz)
|
105
|
-
return if @rules[clazz].nil?
|
106
|
-
|
107
|
-
agg_node = rule_for(clazz)
|
108
|
-
@rules[clazz].each_pair do |field, rule|
|
109
|
-
if run_rule(rule, node)
|
110
|
-
# is this node already included ?
|
111
|
-
unless connected?(field, agg_node, node)
|
112
|
-
agg_node.outgoing(field) << node
|
113
|
-
end
|
114
|
-
else
|
115
|
-
# remove old ?
|
116
|
-
break_connection(field, agg_node, node)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
# recursively add relationships for all the parent classes with rules that also pass for this node
|
121
|
-
if clazz = eval("#{clazz}.superclass")
|
122
|
-
trigger_rules_for_class(node, clazz.to_s)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
# work out if two nodes are connected by a particular relationship
|
127
|
-
# uses the end_node to start with because it's more likely to have less relationships to go through
|
128
|
-
# (just the number of superclasses it has really)
|
129
|
-
def connected?(relationship, start_node, end_node)
|
130
|
-
end_node.incoming(relationship).each do |n|
|
131
|
-
return true if n == start_node
|
132
|
-
end
|
133
|
-
false
|
134
|
-
end
|
135
|
-
|
136
|
-
# sever a direct one-to-one relationship if it exists
|
137
|
-
def break_connection(relationship, start_node, end_node)
|
138
|
-
end_node.rels(relationship).incoming.each do |r|
|
139
|
-
return r.del if r.start_node == start_node
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def run_rule(rule, node)
|
144
|
-
if rule.arity != 1
|
145
|
-
node.wrapper.instance_eval(&rule)
|
146
|
-
else
|
147
|
-
rule.call(node)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
|
154
|
-
# Allows you to group nodes by providing a rule.
|
155
|
-
#
|
156
|
-
# === Example, finding all nodes of a certain class
|
157
|
-
# Just add a rule without a code block, then all nodes of that class will be grouped under the given key (<tt>all</tt>
|
158
|
-
# for the example below).
|
159
|
-
#
|
160
|
-
# class Person
|
161
|
-
# include Neo4j::NodeMixin
|
162
|
-
# rule :all
|
163
|
-
# end
|
164
|
-
#
|
165
|
-
# Then you can get all the nodes of type Person (and siblings) by
|
166
|
-
# Person.all.each {|x| ...}
|
167
|
-
#
|
168
|
-
# === Example, finding all nodes with a given condition on a property
|
169
|
-
#
|
170
|
-
# class Person
|
171
|
-
# include Neo4j::NodeMixin
|
172
|
-
# property :age
|
173
|
-
# rule(:old) { age > 10 }
|
174
|
-
# end
|
175
|
-
#
|
176
|
-
# Now we can find all nodes with a property <tt>age</tt> above 10.
|
177
|
-
#
|
178
|
-
# === Chain Rules
|
179
|
-
#
|
180
|
-
# class NewsStory
|
181
|
-
# include Neo4j::NodeMixin
|
182
|
-
# has_n :readers
|
183
|
-
# rule(:featured) { |node| node[:featured] == true }
|
184
|
-
# rule(:young_readers) { !readers.find{|user| !user.young?}}
|
185
|
-
# end
|
186
|
-
#
|
187
|
-
# You can combine two rules. Let say you want to find all stories which are featured and has young readers:
|
188
|
-
# NewsStory.featured.young_readers.each {...}
|
189
|
-
#
|
190
|
-
# === Trigger Other Rules
|
191
|
-
# You can let one rule trigger another rule.
|
192
|
-
# Let say you have readers of some magazine and want to know if the magazine has old or young readers.
|
193
|
-
# So when a reader change from young to old you want to trigger all the magazine that he reads (a but stupid example)
|
194
|
-
#
|
195
|
-
# Example
|
196
|
-
# class Reader
|
197
|
-
# include Neo4j::NodeMixin
|
198
|
-
# property :age
|
199
|
-
# rule(:young, :trigger => :readers) { age < 15 }
|
200
|
-
# end
|
201
|
-
#
|
202
|
-
# class NewsStory
|
203
|
-
# include Neo4j::NodeMixin
|
204
|
-
# has_n :readers
|
205
|
-
# rule(:young_readers) { !readers.find{|user| !user.young?}}
|
206
|
-
# end
|
207
|
-
#
|
208
|
-
# === Performance Considerations
|
209
|
-
# If you have many rules and many updates this can be a bit slow.
|
210
|
-
# In order to speed it up somewhat you can use the raw java node object instead by providing an argument in your block.
|
211
|
-
#
|
212
|
-
# Example:
|
213
|
-
#
|
214
|
-
# class Person
|
215
|
-
# include Neo4j::NodeMixin
|
216
|
-
# property :age
|
217
|
-
# rule(:old) {|node| node[:age] > 10 }
|
218
|
-
# end
|
219
|
-
#
|
220
|
-
# === Thread Safe ?
|
221
|
-
# Not sure...
|
222
|
-
#
|
223
|
-
module Rule
|
224
|
-
|
225
|
-
# Creates an rule node attached to the Neo4j.ref_node
|
226
|
-
# Can be used to rule all instances of a specific Ruby class.
|
227
|
-
#
|
228
|
-
# Example of usage:
|
229
|
-
# class Person
|
230
|
-
# include Neo4j
|
231
|
-
# rule :all
|
232
|
-
# rule :young { self[:age] < 10 }
|
233
|
-
# end
|
234
|
-
#
|
235
|
-
# p1 = Person.new :age => 5
|
236
|
-
# p2 = Person.new :age => 7
|
237
|
-
# p3 = Person.new :age => 12
|
238
|
-
# Neo4j::Transaction.finish
|
239
|
-
# Person.all # => [p1,p2,p3]
|
240
|
-
# Person.young # => [p1,p2]
|
241
|
-
# p1.young? # => true
|
242
|
-
#
|
243
|
-
def rule(name, props = {}, &block)
|
244
|
-
singelton = class << self;
|
245
|
-
self;
|
246
|
-
end
|
247
|
-
|
248
|
-
# define class methods
|
249
|
-
singelton.send(:define_method, name) do
|
250
|
-
agg_node = Rules.rule_for(self)
|
251
|
-
raise "no rule node for #{name} on #{self}" if agg_node.nil?
|
252
|
-
traversal = agg_node.outgoing(name) # TODO possible to cache this object
|
253
|
-
Rules.fields_for(self).each do |filter_name|
|
254
|
-
traversal.filter_method(filter_name) do |path|
|
255
|
-
path.end_node.rel?(filter_name, :incoming)
|
256
|
-
end
|
257
|
-
end
|
258
|
-
traversal
|
259
|
-
end unless respond_to?(name)
|
260
|
-
|
261
|
-
# define instance methods
|
262
|
-
self.send(:define_method, "#{name}?") do
|
263
|
-
instance_eval &block
|
264
|
-
end
|
265
|
-
|
266
|
-
Rules.add(self, name, props, &block)
|
267
|
-
end
|
268
|
-
|
269
|
-
def inherit_rules_from(clazz)
|
270
|
-
Rules.inherit(clazz, self)
|
271
|
-
end
|
272
|
-
|
273
|
-
# This is typically used for RSpecs to clean up rule nodes created by the #rule method.
|
274
|
-
# It also remove the given class method.
|
275
|
-
def delete_rules
|
276
|
-
singelton = class << self;
|
277
|
-
self;
|
278
|
-
end
|
279
|
-
Rules.fields_for(self).each do |name|
|
280
|
-
singelton.send(:remove_method, name)
|
281
|
-
end
|
282
|
-
Rules.delete(self)
|
283
|
-
end
|
284
|
-
|
285
|
-
# Force to trigger the rules.
|
286
|
-
# You don't normally need that since it will be done automatically.
|
287
|
-
def trigger_rules(node)
|
288
|
-
Rules.trigger_rules(node)
|
289
|
-
end
|
290
|
-
|
291
|
-
end
|
292
|
-
|
293
|
-
Neo4j.unstarted_db.event_handler.add(Rules)
|
294
|
-
end
|
295
|
-
end
|
@@ -1,214 +0,0 @@
|
|
1
|
-
module Neo4j::Mapping
|
2
|
-
|
3
|
-
|
4
|
-
# A DSL for declared relationships has_n and has_one
|
5
|
-
# This DSL will be used to create accessor methods for relationships.
|
6
|
-
# Instead of using the 'raw' Neo4j::NodeMixin#rels method where one needs to know
|
7
|
-
# the name of relationship and direction one can use the generated accessor methods.
|
8
|
-
#
|
9
|
-
# The DSL can also be used to specify a mapping to a Ruby class for a relationship, see Neo4j::Relationships::DeclRelationshipDsl#relationship
|
10
|
-
#
|
11
|
-
# ==== Example
|
12
|
-
#
|
13
|
-
# class Folder
|
14
|
-
# include Neo4j::NodeMixin
|
15
|
-
# property :name
|
16
|
-
# # Declaring a Many relationship to any other node
|
17
|
-
# has_n(:files)
|
18
|
-
# end
|
19
|
-
#
|
20
|
-
# class File
|
21
|
-
# include Neo4j::NodeMixin
|
22
|
-
# # declaring a incoming relationship from Folder's relationship files
|
23
|
-
# has_one(:folder).from(Folder, :files)
|
24
|
-
# end
|
25
|
-
#
|
26
|
-
# The following methods will be generated:
|
27
|
-
# <b>Folder#files</b> :: returns an Enumerable of outgoing nodes for relationship 'files'
|
28
|
-
# <b>Folder#files_rels</b> :: returns an Enumerable of outgoing relationships for relationship 'files'
|
29
|
-
# <b>File#folder</b> :: for adding one node for the relationship 'files' from the outgoing Folder node
|
30
|
-
# <b>File#folder_rel</b> :: for accessing relationship 'files' from the outgoing Folder node
|
31
|
-
# <b>File#folder</b> :: for accessing nodes from relationship 'files' from the outgoing Folder node
|
32
|
-
#
|
33
|
-
class DeclRelationshipDsl
|
34
|
-
include Neo4j::ToJava
|
35
|
-
|
36
|
-
attr_reader :target_class, :direction, :rel_type
|
37
|
-
|
38
|
-
def initialize(method_id, has_one, target_class, params)
|
39
|
-
@direction = :outgoing
|
40
|
-
@method_id = method_id
|
41
|
-
@has_one = has_one
|
42
|
-
@rel_type = method_id
|
43
|
-
@target_class = target_class
|
44
|
-
end
|
45
|
-
|
46
|
-
def to_s
|
47
|
-
"DeclRelationshipDsl #{object_id} dir: #{@direction} rel_id: #{@method_id}, rel_type: #{@rel_type}, target_class:#{@target_class} rel_class:#{@relationship}"
|
48
|
-
end
|
49
|
-
|
50
|
-
def has_one?
|
51
|
-
@has_one
|
52
|
-
end
|
53
|
-
|
54
|
-
def each_node(node, direction, &block) #:nodoc:
|
55
|
-
type = type_to_java(rel_type)
|
56
|
-
dir = dir_to_java(direction)
|
57
|
-
node._java_node.getRelationships(type, dir).each do |rel|
|
58
|
-
other = rel.getOtherNode(node).wrapper
|
59
|
-
block.call other
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def incoming? #:nodoc:
|
64
|
-
@direction == :incoming
|
65
|
-
end
|
66
|
-
|
67
|
-
def single_node(node) #:nodoc:
|
68
|
-
rel = single_relationship(node)
|
69
|
-
rel && rel.other_node(node).wrapper
|
70
|
-
end
|
71
|
-
|
72
|
-
def single_relationship(node) #:nodoc:
|
73
|
-
node._java_node.rel(direction, rel_type)
|
74
|
-
end
|
75
|
-
|
76
|
-
def _all_relationships(node) #:nodoc:
|
77
|
-
type = type_to_java(rel_type)
|
78
|
-
dir = dir_to_java(direction)
|
79
|
-
node._java_node.getRelationships(type, dir)
|
80
|
-
end
|
81
|
-
|
82
|
-
def all_relationships(node) #:nodoc:
|
83
|
-
Neo4j::RelationshipTraverser.new(node._java_node, [rel_type], direction)
|
84
|
-
end
|
85
|
-
|
86
|
-
def create_relationship_to(node, other) # :nodoc:
|
87
|
-
from, to = incoming? ? [other, node] : [node, other]
|
88
|
-
java_type = type_to_java(rel_type)
|
89
|
-
|
90
|
-
rel = from._java_node.create_relationship_to(to._java_node, java_type)
|
91
|
-
rel[:_classname] = relationship_class.to_s if relationship_class
|
92
|
-
rel.wrapper
|
93
|
-
end
|
94
|
-
|
95
|
-
# Specifies an outgoing relationship.
|
96
|
-
# The name of the outgoing class will be used as a prefix for the relationship used.
|
97
|
-
#
|
98
|
-
# ==== Arguments
|
99
|
-
# clazz:: to which class this relationship goes
|
100
|
-
# relationship:: optional, the relationship to use
|
101
|
-
#
|
102
|
-
# ==== Example
|
103
|
-
# class FolderNode
|
104
|
-
# include Neo4j::NodeMixin
|
105
|
-
# has_n(:files).to(FileNode)
|
106
|
-
# end
|
107
|
-
#
|
108
|
-
# folder = FolderNode.new
|
109
|
-
# # generate a relationship between folder and file of type 'FileNode#files'
|
110
|
-
# folder.files << FileNode.new
|
111
|
-
#
|
112
|
-
def to(*args)
|
113
|
-
@direction = :outgoing
|
114
|
-
|
115
|
-
if (args.size > 1)
|
116
|
-
raise "only one argument expected - the class of the node this relationship points to, got #{args.inspect}"
|
117
|
-
elsif (Class === args[0])
|
118
|
-
# handle e.g. has_n(:friends).to(class)
|
119
|
-
@target_class = args[0]
|
120
|
-
@rel_type = "#{@target_class}##{@method_id}"
|
121
|
-
else
|
122
|
-
raise "Expected a class for, got #{args[0]}"
|
123
|
-
end
|
124
|
-
self
|
125
|
-
end
|
126
|
-
|
127
|
-
# Specifies an incoming relationship.
|
128
|
-
# Will use the outgoing relationship given by the from class.
|
129
|
-
#
|
130
|
-
# ==== Example, with prefix FileNode
|
131
|
-
# class FolderNode
|
132
|
-
# include Neo4j::NodeMixin
|
133
|
-
# has_n(:files).to(FileNode)
|
134
|
-
# end
|
135
|
-
#
|
136
|
-
# class FileNode
|
137
|
-
# include Neo4j::NodeMixin
|
138
|
-
# # will only traverse any incoming relationship of type files from node FileNode
|
139
|
-
# has_one(:folder).from(FileNode, :files)
|
140
|
-
# end
|
141
|
-
#
|
142
|
-
# file = FileNode.new
|
143
|
-
# # create an outgoing relationship of type 'FileNode#files' from folder node to file (FileNode is the prefix).
|
144
|
-
# file.folder = FolderNode.new
|
145
|
-
#
|
146
|
-
# ==== Example, without prefix
|
147
|
-
#
|
148
|
-
# class FolderNode
|
149
|
-
# include Neo4j::NodeMixin
|
150
|
-
# has_n(:files)
|
151
|
-
# end
|
152
|
-
#
|
153
|
-
# class FileNode
|
154
|
-
# include Neo4j::NodeMixin
|
155
|
-
# has_one(:folder).from(:files) # will traverse any incoming relationship of type files
|
156
|
-
# end
|
157
|
-
#
|
158
|
-
# file = FileNode.new
|
159
|
-
# # create an outgoing relationship of type 'FileNode#files' from folder node to file
|
160
|
-
# file.folder = FolderNode.new
|
161
|
-
#
|
162
|
-
#
|
163
|
-
def from(*args)
|
164
|
-
@direction = :incoming
|
165
|
-
|
166
|
-
if (args.size > 1)
|
167
|
-
# handle specified (prefixed) relationship, e.g. has_n(:known_by).from(clazz, :type)
|
168
|
-
@rel_type = "#{@target_class}##{args[1]}"
|
169
|
-
@target_class = args[0]
|
170
|
-
other_class_dsl = @target_class._decl_rels[args[1]]
|
171
|
-
if other_class_dsl
|
172
|
-
@relationship = other_class_dsl.relationship_class
|
173
|
-
else
|
174
|
-
puts "WARNING: Unknown outgoing relationship #{args[1]} on #{@target_class}"
|
175
|
-
end
|
176
|
-
elsif (Symbol === args[0])
|
177
|
-
# handle unspecified (unprefixed) relationship, e.g. has_n(:known_by).from(:type)
|
178
|
-
@rel_type = args[0]
|
179
|
-
else
|
180
|
-
raise "Expected a symbol for, got #{args[0]}"
|
181
|
-
end
|
182
|
-
self
|
183
|
-
end
|
184
|
-
|
185
|
-
# Specifies which relationship ruby class to use for the relationship
|
186
|
-
#
|
187
|
-
# ==== Example
|
188
|
-
#
|
189
|
-
# class OrderLine
|
190
|
-
# include Neo4j::RelationshipMixin
|
191
|
-
# property :units
|
192
|
-
# property :unit_price
|
193
|
-
# end
|
194
|
-
#
|
195
|
-
# class Order
|
196
|
-
# property :total_cost
|
197
|
-
# property :dispatched
|
198
|
-
# has_n(:products).to(Product).relationship(OrderLine)
|
199
|
-
# end
|
200
|
-
#
|
201
|
-
# order = Order.new
|
202
|
-
# order.products << Product.new
|
203
|
-
# order.products_rels.first # => OrderLine
|
204
|
-
#
|
205
|
-
def relationship(rel_class)
|
206
|
-
@relationship = rel_class
|
207
|
-
self
|
208
|
-
end
|
209
|
-
|
210
|
-
def relationship_class # :nodoc:
|
211
|
-
@relationship
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|