neo4j-wrapper 0.0.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/Gemfile +10 -0
  2. data/README.rdoc +64 -0
  3. data/lib/db/active_tx_log +1 -0
  4. data/lib/db/index/lucene/node/Person_exact/_0.fdt +0 -0
  5. data/lib/db/index/lucene/node/Person_exact/_0.fdx +0 -0
  6. data/lib/db/index/lucene/node/Person_exact/_0.fnm +1 -0
  7. data/lib/db/index/lucene/node/Person_exact/_0.frq +0 -0
  8. data/lib/db/index/lucene/node/Person_exact/_0.nrm +1 -0
  9. data/lib/db/index/lucene/node/Person_exact/_0.prx +0 -0
  10. data/lib/db/index/lucene/node/Person_exact/_0.tii +0 -0
  11. data/lib/db/index/lucene/node/Person_exact/_0.tis +0 -0
  12. data/lib/db/index/lucene/node/Person_exact/_1.fdt +0 -0
  13. data/lib/db/index/lucene/node/Person_exact/_1.fdx +0 -0
  14. data/lib/db/index/lucene/node/Person_exact/_1.fnm +1 -0
  15. data/lib/db/index/lucene/node/Person_exact/_1.frq +0 -0
  16. data/lib/db/index/lucene/node/Person_exact/_1.nrm +1 -0
  17. data/lib/db/index/lucene/node/Person_exact/_1.prx +0 -0
  18. data/lib/db/index/lucene/node/Person_exact/_1.tii +0 -0
  19. data/lib/db/index/lucene/node/Person_exact/_1.tis +0 -0
  20. data/lib/db/index/lucene/node/Person_exact/_2.fdt +0 -0
  21. data/lib/db/index/lucene/node/Person_exact/_2.fdx +0 -0
  22. data/lib/db/index/lucene/node/Person_exact/_2.fnm +1 -0
  23. data/lib/db/index/lucene/node/Person_exact/_2.frq +0 -0
  24. data/lib/db/index/lucene/node/Person_exact/_2.nrm +1 -0
  25. data/lib/db/index/lucene/node/Person_exact/_2.prx +0 -0
  26. data/lib/db/index/lucene/node/Person_exact/_2.tii +0 -0
  27. data/lib/db/index/lucene/node/Person_exact/_2.tis +0 -0
  28. data/lib/db/index/lucene/node/Person_exact/segments.gen +0 -0
  29. data/lib/db/index/lucene/node/Person_exact/segments_3 +0 -0
  30. data/lib/db/index/lucene-store.db +0 -0
  31. data/lib/db/index/lucene.log.active +0 -0
  32. data/lib/db/index.db +0 -0
  33. data/lib/db/messages.log +826 -0
  34. data/lib/db/neostore +0 -0
  35. data/lib/db/neostore.id +0 -0
  36. data/lib/db/neostore.nodestore.db +0 -0
  37. data/lib/db/neostore.nodestore.db.id +0 -0
  38. data/lib/db/neostore.propertystore.db +0 -0
  39. data/lib/db/neostore.propertystore.db.arrays +0 -0
  40. data/lib/db/neostore.propertystore.db.arrays.id +0 -0
  41. data/lib/db/neostore.propertystore.db.id +0 -0
  42. data/lib/db/neostore.propertystore.db.index +0 -0
  43. data/lib/db/neostore.propertystore.db.index.id +0 -0
  44. data/lib/db/neostore.propertystore.db.index.keys +0 -0
  45. data/lib/db/neostore.propertystore.db.index.keys.id +0 -0
  46. data/lib/db/neostore.propertystore.db.strings +0 -0
  47. data/lib/db/neostore.propertystore.db.strings.id +0 -0
  48. data/lib/db/neostore.relationshipstore.db +0 -0
  49. data/lib/db/neostore.relationshipstore.db.id +0 -0
  50. data/lib/db/neostore.relationshiptypestore.db +0 -0
  51. data/lib/db/neostore.relationshiptypestore.db.id +0 -0
  52. data/lib/db/neostore.relationshiptypestore.db.names +0 -0
  53. data/lib/db/neostore.relationshiptypestore.db.names.id +0 -0
  54. data/lib/db/nioneo_logical.log.active +0 -0
  55. data/lib/db/tm_tx_log.1 +0 -0
  56. data/lib/example.rb +34 -0
  57. data/lib/neo4j/identity_map.rb +109 -0
  58. data/lib/neo4j/node_mixin.rb +74 -0
  59. data/lib/neo4j/relationship_mixin.rb +62 -0
  60. data/lib/neo4j/type_converters/type_converters.rb +333 -0
  61. data/lib/neo4j-wrapper/class_methods.rb +27 -0
  62. data/lib/neo4j-wrapper/find.rb +65 -0
  63. data/lib/neo4j-wrapper/has_n/class_methods.rb +131 -0
  64. data/lib/neo4j-wrapper/has_n/decl_rel.rb +261 -0
  65. data/lib/neo4j-wrapper/has_n/instance_methods.rb +12 -0
  66. data/lib/neo4j-wrapper/has_n/nodes.rb +83 -0
  67. data/lib/neo4j-wrapper/node_mixin/class_methods.rb +53 -0
  68. data/lib/neo4j-wrapper/node_mixin/delegates.rb +140 -0
  69. data/lib/neo4j-wrapper/node_mixin/initialize.rb +43 -0
  70. data/lib/neo4j-wrapper/properties/class_methods.rb +150 -0
  71. data/lib/neo4j-wrapper/relationship_mixin/class_methods.rb +30 -0
  72. data/lib/neo4j-wrapper/relationship_mixin/delegates.rb +110 -0
  73. data/lib/neo4j-wrapper/relationship_mixin/initialize.rb +35 -0
  74. data/lib/neo4j-wrapper/rule/class_methods.rb +204 -0
  75. data/lib/neo4j-wrapper/rule/event_listener.rb +66 -0
  76. data/lib/neo4j-wrapper/rule/functions/count.rb +45 -0
  77. data/lib/neo4j-wrapper/rule/functions/function.rb +76 -0
  78. data/lib/neo4j-wrapper/rule/functions/sum.rb +31 -0
  79. data/lib/neo4j-wrapper/rule/instance_methods.rb +16 -0
  80. data/lib/neo4j-wrapper/rule/neo4j_core_ext/traverser.rb +29 -0
  81. data/lib/neo4j-wrapper/rule/rule.rb +134 -0
  82. data/lib/neo4j-wrapper/rule/rule_node.rb +205 -0
  83. data/lib/neo4j-wrapper/version.rb +5 -0
  84. data/lib/neo4j-wrapper/wrapper.rb +38 -0
  85. data/lib/neo4j-wrapper.rb +35 -0
  86. data/lib/test.rb +61 -0
  87. data/neo4j-wrapper.gemspec +31 -0
  88. metadata +162 -0
@@ -0,0 +1,65 @@
1
+ module Neo4j
2
+ module Wrapper
3
+ module Find
4
+ Neo4j::Core::Index::ClassMethods.send(:alias_method, :_orig_find, :find)
5
+
6
+ # If the #ref_node_for_class returns an object implementing the method #_index_prefix it
7
+ # will use that as prefix, otherwise the empty string.
8
+ # @return [String] the prefix name of the index
9
+ def index_prefix
10
+ return "" unless Neo4j.running?
11
+ return "" unless respond_to?(:ref_node_for_class)
12
+ ref_node = ref_node_for_class.wrapper
13
+ prefix = ref_node.send(:index_prefix) if ref_node.respond_to?(:index_prefix)
14
+ prefix ? prefix + "_" : ""
15
+ end
16
+
17
+
18
+ # @return [String] the name of the index, with index prefix
19
+ def _index_name
20
+ to_s.gsub("::", '_')
21
+ end
22
+
23
+ # Fall back to the threadlocal ref node by default.
24
+ # You can set your own reference node using the #ref_node method
25
+ # @return [Neo4j::Node] returns the Neo4j.ref_node
26
+ def ref_node_for_class
27
+ Neo4j.ref_node
28
+ end
29
+
30
+ # Assigns the reference node for a class via a supplied block.
31
+ #
32
+ # @example of usage:
33
+ # class Person
34
+ # include Neo4j::NodeMixin
35
+ # ref_node { Neo4j.default_ref_node }
36
+ # end
37
+ #
38
+ def ref_node(&block)
39
+ singleton = class << self;
40
+ self;
41
+ end
42
+ singleton.send(:define_method, :ref_node_for_class) { block.call }
43
+ end
44
+
45
+ # Overrides the Neo4j::Core::Index::ClassMethods#find method to check
46
+ # if any of the query parameters needs to be converted, (e.g. DateTime to Fixnum)
47
+ #
48
+ # @example
49
+ # Person.find(:since => (1.year.ago .. Time.now))
50
+ # @see http://rdoc.info/github/andreasronge/neo4j-core/Neo4j/Core/Index/Indexer#find-instance_method Neo4j::Core::Index::ClassMethods#find
51
+ def find(*query_params)
52
+ query = query_params.first
53
+ if query.is_a?(Hash)
54
+ query.each_pair do |k, v|
55
+ converter = _converter(k)
56
+ value = v.is_a?(Range) ? Range.new(converter.to_java(v.begin), converter.to_java(v.end), v.exclude_end?) : converter.to_java(v)
57
+ query[k] = value
58
+ end
59
+ end
60
+ _orig_find(*query_params)
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,131 @@
1
+ module Neo4j
2
+ module Wrapper
3
+ module HasN
4
+ module ClassMethods
5
+
6
+ # @return [Hash] a hash of all relationship and its configuration defined by has_n and has_one
7
+ def _decl_rels
8
+ @_decl_rels ||= {}
9
+ end
10
+
11
+ # make sure the inherited classes inherit the <tt>_decl_rels</tt> hash
12
+ def inherited(klass)
13
+ copy = _decl_rels.clone
14
+ copy.each_pair{|k,v| copy[k] = v.inherit_new}
15
+ klass.instance_variable_set(:@_decl_rels, copy)
16
+ super
17
+ end
18
+
19
+
20
+ # Specifies a relationship between two node classes.
21
+ # Generates assignment and accessor methods for the given relationship.
22
+ # Both incoming and outgoing relationships can be declared, see {Neo4j::Wrapper::HasN::DeclRel}
23
+ #
24
+ # @example has_n(:files)
25
+ #
26
+ # class FolderNode
27
+ # include Ne4j::NodeMixin
28
+ # has_n(:files)
29
+ # end
30
+ #
31
+ # folder = FolderNode.new
32
+ # folder.files << Neo4j::Node.new << Neo4j::Node.new
33
+ # folder.files.inject {...}
34
+ #
35
+ # FolderNode.files #=> 'files' the name of the relationship
36
+ #
37
+ # @example has_n(x).to(...)
38
+ #
39
+ # # You can declare which class it has relationship to.
40
+ # # The generated relationships will be prefixed with the name of that class.
41
+ # class FolderNode
42
+ # include Ne4j::NodeMixin
43
+ # has_n(:files).to(File)
44
+ # end
45
+ #
46
+ # FolderNode.files #=> 'File#files' the name of the relationship
47
+ #
48
+ # @example has_n(x).from(class, has_n_name)
49
+ #
50
+ # # generate accessor method for traversing and adding relationship on incoming nodes.
51
+ # class FileNode
52
+ # include Ne4j::NodeMixin
53
+ # has_one(:folder).from(FolderNode, :files)
54
+ # end
55
+ #
56
+ #
57
+ # @return [Neo4j::Wrapper::HasN::DeclRel] a DSL object where the has_n relationship can be futher specified
58
+ def has_n(rel_type)
59
+ clazz = self
60
+ module_eval(%Q{
61
+ def #{rel_type}
62
+ dsl = _decl_rels_for('#{rel_type}'.to_sym)
63
+ Neo4j::Wrapper::HasN::Nodes.new(self, dsl)
64
+ end}, __FILE__, __LINE__)
65
+
66
+
67
+ module_eval(%Q{
68
+ def #{rel_type}_rels
69
+ dsl = _decl_rels_for('#{rel_type}'.to_sym)
70
+ dsl.all_relationships(self)
71
+ end}, __FILE__, __LINE__)
72
+
73
+ instance_eval(%Q{
74
+ def #{rel_type}
75
+ _decl_rels[:#{rel_type}].rel_type.to_s
76
+ end}, __FILE__, __LINE__)
77
+
78
+ _decl_rels[rel_type.to_sym] = DeclRel.new(rel_type, false, clazz)
79
+ end
80
+
81
+
82
+ # Specifies a relationship between two node classes.
83
+ # Generates assignment and accessor methods for the given relationship
84
+ # Old relationship is deleted when a new relationship is assigned.
85
+ # Both incoming and outgoing relationships can be declared, see {Neo4j::Wrapper::HasN::DeclRel}
86
+ #
87
+ # @example
88
+ #
89
+ # class FileNode
90
+ # include Ne4j::NodeMixin
91
+ # has_one(:folder)
92
+ # end
93
+ #
94
+ # file = FileNode.new
95
+ # file.folder = Neo4j::Node.new
96
+ # file.folder # => the node above
97
+ # file.folder_rel # => the relationship object between those nodes
98
+ #
99
+ # @return [Neo4j::Wrapper::HasN::DeclRel] a DSL object where the has_one relationship can be futher specified
100
+ def has_one(rel_type)
101
+ clazz = self
102
+ module_eval(%Q{def #{rel_type}=(value)
103
+ dsl = _decl_rels_for(:#{rel_type})
104
+ rel = dsl.single_relationship(self)
105
+ rel.del unless rel.nil?
106
+ dsl.create_relationship_to(self, value) if value
107
+ end}, __FILE__, __LINE__)
108
+
109
+ module_eval(%Q{def #{rel_type}
110
+ dsl = _decl_rels_for(:#{rel_type})
111
+ dsl.single_node(self)
112
+ end}, __FILE__, __LINE__)
113
+
114
+ module_eval(%Q{def #{rel_type}_rel
115
+ dsl = _decl_rels_for(:#{rel_type})
116
+ dsl.single_relationship(self)
117
+ end}, __FILE__, __LINE__)
118
+
119
+ instance_eval(%Q{
120
+ def #{rel_type}
121
+ _decl_rels[:#{rel_type}].rel_type.to_s
122
+ end}, __FILE__, __LINE__)
123
+
124
+ _decl_rels[rel_type.to_sym] = DeclRel.new(rel_type, true, clazz)
125
+ end
126
+
127
+ end
128
+ end
129
+ end
130
+
131
+ end
@@ -0,0 +1,261 @@
1
+ module Neo4j
2
+ module Wrapper
3
+ module HasN
4
+
5
+
6
+ # A DSL for declared relationships has_n and has_one
7
+ # This DSL will be used to create accessor methods for relationships.
8
+ # Instead of using the 'raw' Neo4j::NodeMixin#rels method where one needs to know
9
+ # the name of relationship and direction one can use the generated accessor methods.
10
+ #
11
+ # The DSL can also be used to specify a mapping to a Ruby class for a relationship, see Neo4j::HasN::DeclRelationshipDsl#relationship
12
+ #
13
+ # @example
14
+ #
15
+ # class Folder
16
+ # include Neo4j::NodeMixin
17
+ # property :name
18
+ # # Declaring a Many relationship to any other node
19
+ # has_n(:files)
20
+ # end
21
+ #
22
+ # class File
23
+ # include Neo4j::NodeMixin
24
+ # # declaring a incoming relationship from Folder's relationship files
25
+ # has_one(:folder).from(Folder, :files)
26
+ # end
27
+ #
28
+ # The following methods will be generated:
29
+ # <b>Folder#files</b> :: returns an Enumerable of outgoing nodes for relationship 'files'
30
+ # <b>Folder#files_rels</b> :: returns an Enumerable of outgoing relationships for relationship 'files'
31
+ # <b>File#folder</b> :: for adding one node for the relationship 'files' from the outgoing Folder node
32
+ # <b>File#folder_rel</b> :: for accessing relationship 'files' from the outgoing Folder node
33
+ # <b>File#folder</b> :: for accessing nodes from relationship 'files' from the outgoing Folder node
34
+ #
35
+ class DeclRel
36
+ attr_reader :target_class, :source_class, :dir, :rel_type
37
+
38
+ def initialize(method_id, has_one, target_class)
39
+ @method_id = method_id
40
+ @has_one = has_one
41
+ @target_class = target_class
42
+ @dir = :outgoing
43
+ @rel_type = method_id.to_s
44
+ @source_class = target_class
45
+ end
46
+
47
+ def inherit_new
48
+ base = self
49
+ dr = DeclRel.new(@method_id, @has_one, @target_class)
50
+ dr.instance_eval do
51
+ @dir = base.dir
52
+ @rel_type = base.rel_type
53
+ @source_class = base.source_class
54
+ end
55
+ dr
56
+ end
57
+
58
+ def to_s
59
+ "DeclRel #{object_id} dir: #{@dir} rel_id: #{@method_id}, rel_type: #{@rel_type}, target_class:#{@target_class} rel_class:#{@relationship}"
60
+ end
61
+
62
+ # @return [true, false]
63
+ def has_one?
64
+ @has_one
65
+ end
66
+
67
+ # @return [true, false]
68
+ def has_n?
69
+ !@has_one
70
+ end
71
+
72
+ # @return [true,false]
73
+ def incoming? #:nodoc:
74
+ @dir == :incoming
75
+ end
76
+
77
+
78
+ # Specifies an outgoing relationship.
79
+ # The name of the outgoing class will be used as a prefix for the relationship used.
80
+ #
81
+ # @example Example
82
+ # class FolderNode
83
+ # include Neo4j::NodeMixin
84
+ # has_n(:files).to(FileNode)
85
+ # end
86
+ #
87
+ # folder = FolderNode.new
88
+ # # generate a relationship between folder and file of type 'FileNode#files'
89
+ # folder.files << FileNode.new
90
+ #
91
+ # @example without prefix
92
+ #
93
+ # class FolderNode
94
+ # include Neo4j::NodeMixin
95
+ # has_n(:files).to(:contains)
96
+ # end
97
+ #
98
+ # file = FileNode.new
99
+ # # create an outgoing relationship of type 'contains' from folder node to file
100
+ # folder.files << FolderNode.new
101
+ #
102
+ # @param [Class] target the other class to which this relationship goes
103
+ # @return self
104
+ def to(target)
105
+ @dir = :outgoing
106
+
107
+ if Class === target
108
+ # handle e.g. has_n(:friends).to(class)
109
+ @target_class = target
110
+ @rel_type = "#{@source_class}##{@method_id}"
111
+ elsif Symbol === target
112
+ # handle e.g. has_n(:friends).to(:knows)
113
+ @rel_type = target.to_s
114
+ else
115
+ raise "Expected a class or a symbol for, got #{target}/#{target.class}"
116
+ end
117
+ self
118
+ end
119
+
120
+ # Specifies an incoming relationship.
121
+ # Will use the outgoing relationship given by the from class.
122
+ #
123
+ # @example with prefix FileNode
124
+ # class FolderNode
125
+ # include Neo4j::NodeMixin
126
+ # has_n(:files).to(FileNode)
127
+ # end
128
+ #
129
+ # class FileNode
130
+ # include Neo4j::NodeMixin
131
+ # # will only traverse any incoming relationship of type files from node FileNode
132
+ # has_one(:folder).from(FolderNode, :files)
133
+ # end
134
+ #
135
+ # file = FileNode.new
136
+ # # create an outgoing relationship of type 'FileNode#files' from folder node to file (FileNode is the prefix).
137
+ # file.folder = FolderNode.new
138
+ #
139
+ # @example without prefix
140
+ #
141
+ # class FolderNode
142
+ # include Neo4j::NodeMixin
143
+ # has_n(:files)
144
+ # end
145
+ #
146
+ # class FileNode
147
+ # include Neo4j::NodeMixin
148
+ # has_one(:folder).from(:files) # will traverse any incoming relationship of type files
149
+ # end
150
+ #
151
+ # file = FileNode.new
152
+ # # create an outgoing relationship of type 'files' from folder node to file
153
+ # file.folder = FolderNode.new
154
+ #
155
+ #
156
+ def from(*args)
157
+ @dir = :incoming
158
+
159
+ if args.size > 1
160
+ # handle specified (prefixed) relationship, e.g. has_n(:known_by).from(clazz, :type)
161
+ @target_class = args[0]
162
+ @rel_type = "#{@target_class}##{args[1]}"
163
+ @relationship_name = args[1].to_sym
164
+ elsif Symbol === args[0]
165
+ # handle unspecified (unprefixed) relationship, e.g. has_n(:known_by).from(:type)
166
+ @rel_type = args[0].to_s
167
+ else
168
+ raise "Expected a symbol for, got #{args[0]}"
169
+ end
170
+ self
171
+ end
172
+
173
+ # Specifies which relationship ruby class to use for the relationship
174
+ #
175
+ # @example
176
+ #
177
+ # class OrderLine
178
+ # include Neo4j::RelationshipMixin
179
+ # property :units
180
+ # property :unit_price
181
+ # end
182
+ #
183
+ # class Order
184
+ # property :total_cost
185
+ # property :dispatched
186
+ # has_n(:products).to(Product).relationship(OrderLine)
187
+ # end
188
+ #
189
+ # order = Order.new
190
+ # order.products << Product.new
191
+ # order.products_rels.first # => OrderLine
192
+ #
193
+ def relationship(rel_class)
194
+ @relationship = rel_class
195
+ self
196
+ end
197
+
198
+
199
+ # @private
200
+ def relationship_class # :nodoc:
201
+ if !@relationship_name.nil? && @relationship.nil?
202
+ other_class_dsl = @target_class._decl_rels[@relationship_name]
203
+ if other_class_dsl
204
+ @relationship = other_class_dsl.relationship_class
205
+ else
206
+ Neo4j.logger.warn "Unknown outgoing relationship #{@relationship_name} on #{@target_class}"
207
+ end
208
+ end
209
+ @relationship
210
+ end
211
+
212
+ # @private
213
+ def each_node(node, &block)
214
+ node.rels(dir, rel_type).each do |rel|
215
+ block.call(rel.other_node(node))
216
+ end
217
+ end
218
+
219
+ # @private
220
+ def _each_node(node, &block) #:nodoc:
221
+ node._rels(dir, rel_type).each do |rel|
222
+ block.call rel._other_node(node)
223
+ end
224
+ end
225
+
226
+ # @private
227
+ def single_node(node)
228
+ rel = single_relationship(node)
229
+ rel && rel.other_node(node)
230
+ end
231
+
232
+ # @private
233
+ def single_relationship(node) #:nodoc:
234
+ node.rel(dir, rel_type)
235
+ end
236
+
237
+ # @private
238
+ def _all_relationships(node) #:nodoc:
239
+ node._rels(dir, rel_type)
240
+ end
241
+
242
+ # @private
243
+ def all_relationships(node)
244
+ node.rels(dir, rel_type)
245
+ end
246
+
247
+ # @private
248
+ def create_relationship_to(node, other) # :nodoc:
249
+ from, to = incoming? ? [other, node] : [node, other]
250
+
251
+ if relationship_class
252
+ relationship_class.new(@rel_type, from._java_node, to._java_node)
253
+ else
254
+ Neo4j::Relationship.new(@rel_type, from, to)
255
+ end
256
+ end
257
+
258
+ end
259
+ end
260
+ end
261
+ end
@@ -0,0 +1,12 @@
1
+ module Neo4j
2
+ module Wrapper
3
+ module HasN
4
+ # The {Neo4j::Wrapper::HasN::ClassMethods} generates has_n relationship accessor methods.
5
+ module InstanceMethods
6
+ def _decl_rels_for(rel_type)
7
+ self.class._decl_rels[rel_type]
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,83 @@
1
+ module Neo4j
2
+ module Wrapper
3
+ module HasN
4
+
5
+ # The object created by a has_n or has_one Neo4j::NodeMixin class method which enables creating and traversal of nodes.
6
+ #
7
+ # @see Neo4j::Wrapper::HasN::ClassMethods
8
+ class Nodes
9
+ include Enumerable
10
+ include Neo4j::Core::ToJava
11
+
12
+ def initialize(node, decl_rel) # :nodoc:
13
+ @node = node
14
+ @decl_rel = decl_rel
15
+ end
16
+
17
+ def to_s
18
+ "HasN::Nodes [#{@decl_rel.dir}, id: #{@node.neo_id} type: #{@decl_rel && @decl_rel.rel_type} decl_rel:#{@decl_rel}]"
19
+ end
20
+
21
+ # Traverse the relationship till the index position
22
+ # @return [Neo4j::NodeMixin,Neo4j::Node,nil] the node at the given position
23
+ def [](index)
24
+ i = 0
25
+ each { |x| return x if i == index; i += 1 }
26
+ nil # out of index
27
+ end
28
+
29
+ # Pretend we are an array - this is necessarily for Rails actionpack/actionview/formhelper to work with this
30
+ def is_a?(type)
31
+ # ActionView requires this for nested attributes to work
32
+ return true if Array == type
33
+ super
34
+ end
35
+
36
+ # Required by the Enumerable mixin.
37
+ def each
38
+ @decl_rel.each_node(@node) { |n| yield n } # Should use yield here as passing &block through doesn't always work (why?)
39
+ end
40
+
41
+ # returns none wrapped nodes, you may get better performance using this method
42
+ def _each
43
+ @decl_rel._each_node(@node) { |n| yield n }
44
+ end
45
+
46
+ # Returns an real ruby array.
47
+ def to_ary
48
+ self.to_a
49
+ end
50
+
51
+ # Returns true if there are no node in this type of relationship
52
+ def empty?
53
+ first == nil
54
+ end
55
+
56
+
57
+ # Creates a relationship instance between this and the other node.
58
+ # Returns the relationship object
59
+ def new(other)
60
+ @decl_rel.create_relationship_to(@node, other)
61
+ end
62
+
63
+
64
+ # Creates a relationship between this and the other node.
65
+ #
66
+ # @example Person includes the Neo4j::NodeMixin and declares a has_n :friends
67
+ #
68
+ # p = Person.new # Node has declared having a friend type of relationship
69
+ # n1 = Node.new
70
+ # n2 = Node.new
71
+ #
72
+ # p.friends << n2 << n3
73
+ #
74
+ # @return self
75
+ def <<(other)
76
+ @decl_rel.create_relationship_to(@node, other)
77
+ self
78
+ end
79
+ end
80
+
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,53 @@
1
+ module Neo4j
2
+ module Wrapper
3
+ module NodeMixin
4
+ module ClassMethods
5
+
6
+ # Creates a new node or loads an already existing Neo4j node.
7
+ #
8
+ # You can use two callback method to initialize the node
9
+ # init_on_load - this method is called when the node is loaded from the database
10
+ # init_on_create - called when the node is created, will be provided with the same argument as the new method
11
+ #
12
+ # == Does
13
+ # * sets the neo4j property '_classname' to self.class.to_s
14
+ # * creates a neo4j node java object (in @_java_node)
15
+ #
16
+ # If you want to provide your own initialize method you should instead implement the
17
+ # method init_on_create method.
18
+ #
19
+ # @example Create your own Ruby wrapper around a Neo4j::Node java object
20
+ # class MyNode
21
+ # include Neo4j::NodeMixin
22
+ # end
23
+ #
24
+ # node = MyNode.new(:name => 'jimmy', :age => 23)
25
+ #
26
+ # @example Using your own initialize method
27
+ # class MyNode
28
+ # include Neo4j::NodeMixin
29
+ #
30
+ # def init_on_create(name, age)
31
+ # self[:name] = name
32
+ # self[:age] = age
33
+ # end
34
+ # end
35
+ #
36
+ # node = MyNode.new('jimmy', 23)
37
+ #
38
+ # @param args typically a hash of properties, but could be anything which will be handled in the super method
39
+ # @return the object return from the super method
40
+ def new(*args)
41
+ node = Neo4j::Node.create
42
+ wrapped_node = super()
43
+ Neo4j::IdentityMap.add(node, wrapped_node)
44
+ wrapped_node.init_on_load(node)
45
+ wrapped_node.init_on_create(*args)
46
+ wrapped_node
47
+ end
48
+
49
+ alias_method :create, :new
50
+ end
51
+ end
52
+ end
53
+ end