neo4j 1.0.0.beta.20 → 3.0.0.alpha.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|