neo4j-core 0.0.15-java → 2.0.0.alpha.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/Gemfile +2 -2
  2. data/README.rdoc +12 -192
  3. data/lib/neo4j-core.rb +3 -19
  4. data/lib/neo4j-core/database.rb +5 -4
  5. data/lib/neo4j-core/event_handler.rb +1 -1
  6. data/lib/neo4j-core/index/class_methods.rb +41 -27
  7. data/lib/neo4j-core/index/index.rb +4 -3
  8. data/lib/neo4j-core/index/index_config.rb +23 -30
  9. data/lib/neo4j-core/index/indexer.rb +53 -65
  10. data/lib/neo4j-core/index/indexer_registry.rb +2 -2
  11. data/lib/neo4j-core/index/lucene_query.rb +42 -53
  12. data/lib/neo4j-core/node/class_methods.rb +4 -4
  13. data/lib/neo4j-core/node/node.rb +8 -1
  14. data/lib/neo4j-core/property/property.rb +3 -1
  15. data/lib/neo4j-core/relationship/relationship.rb +10 -8
  16. data/lib/neo4j-core/rels/rels.rb +4 -9
  17. data/lib/neo4j-core/rels/traverser.rb +27 -13
  18. data/lib/neo4j-core/traversal/prune_evaluator.rb +2 -2
  19. data/lib/neo4j-core/traversal/traverser.rb +27 -122
  20. data/lib/neo4j-core/type_converters/type_converters.rb +287 -0
  21. data/lib/neo4j-core/version.rb +1 -1
  22. data/lib/neo4j-core/version.rb~ +3 -0
  23. data/lib/neo4j/config.rb +6 -3
  24. data/lib/neo4j/neo4j.rb +22 -51
  25. data/lib/neo4j/node.rb +0 -27
  26. data/lib/neo4j/relationship.rb +0 -25
  27. data/lib/test.rb +27 -0
  28. data/neo4j-core.gemspec +2 -2
  29. metadata +11 -17
  30. data/lib/neo4j-core/cypher/cypher.rb +0 -969
  31. data/lib/neo4j-core/cypher/result_wrapper.rb +0 -48
  32. data/lib/neo4j-core/hash_with_indifferent_access.rb +0 -165
  33. data/lib/neo4j-core/index/unique_factory.rb +0 -54
  34. data/lib/neo4j-core/property/java.rb +0 -59
  35. data/lib/neo4j-core/wrapper/class_methods.rb +0 -22
  36. data/lib/neo4j-core/wrapper/wrapper.rb +0 -20
  37. data/lib/neo4j/algo.rb +0 -300
  38. data/lib/neo4j/cypher.rb +0 -180
@@ -61,11 +61,11 @@ module Neo4j
61
61
  end
62
62
 
63
63
  # Loads a node or wrapped node given a native java node or an id.
64
- # If there is a Ruby wrapper for the node then it will create and return a Ruby object that will
65
- # wrap the java node.
64
+ # If there is a Ruby wrapper for the node then it will create a Ruby object that will
65
+ # wrap the java node (see Neo4j::NodeMixin).
66
+ # To implement a wrapper you must implement a wrapper class method in the Neo4j::Node or Neo4j::Relationship.
66
67
  #
67
- # @param [nil, #to_i] node_id the neo4j node id
68
- # @return [Object, Neo4j::Node, nil] If the node does not exist it will return nil otherwise the loaded node or wrapped node.
68
+ # @return [Object, nil] If the node does not exist it will return nil otherwise the loaded node or wrapped node.
69
69
  def load(node_id, db = Neo4j.started_db)
70
70
  node = _load(node_id, db)
71
71
  node && node.wrapper
@@ -31,7 +31,14 @@ module Neo4j
31
31
  Neo4j::Node.exist?(self)
32
32
  end
33
33
 
34
- # Overrides the class so that the java object feels like a Ruby object.
34
+ # Tries to load the wrapper object for this node by calling the class #wrapper method.
35
+ # This allows you to create a custom Ruby wrapper class around the Neo4j::Node.
36
+ # This is for example done in the <tt>neo4j<//t> ruby gem <tt>Neo4j::NodeMixin</tt>
37
+ # @return a wrapper object or self
38
+ def wrapper
39
+ self.class.respond_to?(:wrapper) ? self.class.wrapper(node) : self
40
+ end
41
+
35
42
  def class
36
43
  Neo4j::Node
37
44
  end
@@ -5,7 +5,9 @@ module Neo4j
5
5
  # @return [Hash] all properties plus the id of the node with the key <tt>_neo_id</tt>
6
6
  def props
7
7
  ret = {"_neo_id" => neo_id}
8
- property_keys.each do |key|
8
+ iter = get_property_keys.iterator
9
+ while (iter.hasNext) do
10
+ key = iter.next
9
11
  ret[key] = get_property(key)
10
12
  end
11
13
  ret
@@ -3,19 +3,16 @@ module Neo4j
3
3
  module Relationship
4
4
 
5
5
  # Same as Java::OrgNeo4jGraphdb::Relationship#getEndNode
6
- # @see http://api.neo4j.org/1.6.1/org/neo4j/graphdb/Relationship.html#getEndNode()
7
6
  def _end_node
8
7
  get_end_node
9
8
  end
10
9
 
11
10
  # Same as Java::OrgNeo4jGraphdb::Relationship#getStartNode
12
- # @see http://api.neo4j.org/1.6.1/org/neo4j/graphdb/Relationship.html#getStartNode()
13
11
  def _start_node
14
12
  get_start_node
15
13
  end
16
14
 
17
15
  # Same as Java::OrgNeo4jGraphdb::Relationship#getOtherNode
18
- # @see http://api.neo4j.org/1.6.1/org/neo4j/graphdb/Relationship.html#getOtherNode()
19
16
  def _other_node(node)
20
17
  get_other_node(node)
21
18
  end
@@ -52,7 +49,6 @@ module Neo4j
52
49
  #
53
50
  # @param [Neo4j::Node] node the node that we don't want to return
54
51
  # @return [Neo4j::Node] the other node wrapper
55
- # @see #_other_node
56
52
  def other_node(node)
57
53
  _other_node(node._java_node).wrapper
58
54
  end
@@ -60,7 +56,7 @@ module Neo4j
60
56
 
61
57
  # same as #_java_rel
62
58
  # Used so that we have same method for both relationship and nodes
63
- def _java_entity
59
+ def wrapped_entity
64
60
  self
65
61
  end
66
62
 
@@ -74,15 +70,21 @@ module Neo4j
74
70
  Neo4j::Relationship.exist?(self)
75
71
  end
76
72
 
73
+ # Loads the wrapper using the #wrapper class method if it exists, otherwise return self.
74
+ def wrapper
75
+ self.class.respond_to?(:wrapper) ? self.class.wrapper(node) : self
76
+ end
77
+
78
+
77
79
  # Returns the relationship name
78
80
  #
79
81
  # @example
80
82
  # a = Neo4j::Node.new
81
83
  # a.outgoing(:friends) << Neo4j::Node.new
82
- # a.rels.first.rel_type # => :friends
83
- # @return [Symbol] the type of the relationship
84
+ # a.rels.first.rel_type # => 'friends'
85
+ # @return [String] the type of the relationship
84
86
  def rel_type
85
- getType().name().to_sym
87
+ getType().name()
86
88
  end
87
89
 
88
90
  def class
@@ -2,8 +2,6 @@ module Neo4j
2
2
  module Core
3
3
  # Contains methods for traversing relationship object of depth one from one node.
4
4
  module Rels
5
-
6
-
7
5
  # Returns the only node of a given type and direction that is attached to this node, or nil.
8
6
  # This is a convenience method that is used in the commonly occuring situation where a node has exactly zero or one relationships of a given type and direction to another node.
9
7
  # Typically this invariant is maintained by the rest of the code: if at any time more than one such relationships exist, it is a fatal error that should generate an exception.
@@ -78,9 +76,7 @@ module Neo4j
78
76
  #
79
77
  # @see Neo4j::Core::Node#wrapper #wrapper - The method used wrap to the node in a Ruby object if the node was found
80
78
  # @see Neo4j::Relationship#rel_type
81
- # @raise an exception if the first parameter is not <tt>:both</tt>, <tt>;outgoing</tt> or <tt>:incoming</tt>
82
- def rels(dir=:both, *types)
83
- raise "Illegal argument, first argument must be :both, :incoming or :outgoing, got #{dir.inspect}" unless [:incoming, :outgoing, :both].include?(dir)
79
+ def rels(dir, *types)
84
80
  Neo4j::Core::Rels::Traverser.new(self, types, dir)
85
81
  end
86
82
 
@@ -118,15 +114,14 @@ module Neo4j
118
114
  # @return [Enumerable] of Neo4j::Relationship objects
119
115
  def _rels(dir=:both, *types)
120
116
  if types.size > 1
121
- get_relationships(ToJava.dir_to_java(dir), ToJava.types_to_java(types)).iterator
117
+ get_relationships(ToJava.dir_to_java(dir), ToJava.types_to_java(types))
122
118
  elsif types.size == 1
123
- get_relationships(ToJava.type_to_java(types[0]), ToJava.dir_to_java(dir)).iterator
119
+ get_relationships(ToJava.type_to_java(types[0]), ToJava.dir_to_java(dir))
124
120
  else
125
- get_relationships(ToJava.dir_to_java(dir)).iterator
121
+ get_relationships(ToJava.dir_to_java(dir))
126
122
  end
127
123
  end
128
124
 
129
-
130
125
  # Check if the given relationship exists
131
126
  # Returns true if there are one or more relationships from this node to other nodes
132
127
  # with the given relationship.
@@ -26,8 +26,10 @@ module Neo4j
26
26
 
27
27
  # Implements the Ruby Enumerable mixin
28
28
  def each
29
- iterator.each do |rel|
30
- yield rel.wrapper if match_between?(rel)
29
+ iter = iterator
30
+ while (iter.has_next())
31
+ rel = iter.next
32
+ yield rel.wrapper if match_to_other?(rel)
31
33
  end
32
34
  end
33
35
 
@@ -41,30 +43,42 @@ module Neo4j
41
43
  @node._rels(@dir, *@types)
42
44
  end
43
45
 
46
+ # @return [Fixnum] the size of all matched relationship, also check if it #to_other node
47
+ # @see #to_other
48
+ def size
49
+ c = 0
50
+ iter = iterator
51
+ while (iter.has_next())
52
+ rel = iter.next
53
+ next unless match_to_other?(rel)
54
+ c += 1
55
+ end
56
+ c
57
+ end
58
+
59
+
44
60
  # @return [true,false] true if it match the specified other node
45
- # @see #between
46
- def match_between?(rel)
47
- if @between.nil?
61
+ # @see #to_other
62
+ def match_to_other?(rel)
63
+ if @to_other.nil?
48
64
  true
49
65
  elsif @dir == :outgoing
50
- rel._end_node == @between
66
+ rel._end_node == @to_other
51
67
  elsif @dir == :incoming
52
- rel._start_node == @between
68
+ rel._start_node == @to_other
53
69
  else
54
- rel._start_node == @between || rel._end_node == @between
70
+ rel._start_node == @to_other || rel._end_node == @to_other
55
71
  end
56
72
  end
57
73
 
58
74
  # Specifies that we only want relationship to the given node
59
- # @param [Neo4j::Node] between a node or an object that implements the Neo4j::Core::Equal mixin
75
+ # @param [Neo4j::Node] to_other a node or an object that implements the Neo4j::Core::Equal mixin
60
76
  # @return self
61
- def between(between)
62
- @between = between
77
+ def to_other(to_other)
78
+ @to_other = to_other
63
79
  self
64
80
  end
65
81
 
66
- alias_method :to_other, :between
67
-
68
82
  # Deletes all the relationships
69
83
  def del
70
84
  each { |rel| rel.del }
@@ -1,9 +1,9 @@
1
1
  module Neo4j
2
2
  module Core
3
3
 
4
+ # Implements the Neo4j PruneEvaluator Java interface, only used internally.
5
+ # @private
4
6
  module Traversal
5
- # Implements the Neo4j PruneEvaluator Java interface, only used internally.
6
- # @private
7
7
  class PruneEvaluator
8
8
  include Java::OrgNeo4jGraphdbTraversal::PruneEvaluator
9
9
 
@@ -2,54 +2,6 @@ module Neo4j
2
2
  module Core
3
3
  module Traversal
4
4
 
5
- class CypherQuery
6
- include Enumerable
7
- attr_accessor :query, :return_variable
8
-
9
- def initialize(start_id, dir, types, query_hash=nil, &block)
10
- this = self
11
-
12
- rel_type = ":#{types.map{|x| "`#{x}`"}.join('|')}"
13
-
14
- @query = Neo4j::Cypher.new do
15
- default_ret = node(:default_ret)
16
- n = node(start_id)
17
- case dir
18
- when :outgoing then
19
- n > rel_type > default_ret
20
- when :incoming then
21
- n < rel_type < default_ret
22
- when :both then
23
- n - rel_type - default_ret
24
- end
25
-
26
- # where statement
27
- ret_maybe = block && self.instance_exec(default_ret, &block)
28
- ret = ret_maybe.respond_to?(:var_name) ? ret_maybe : default_ret
29
- if query_hash
30
- expr = []
31
- query_hash.each{|pair| expr << (ret[pair[0]] == pair[1])}.to_a
32
- expr.each_with_index do |obj, i|
33
- Neo4j::Core::Cypher::ExprOp.new(obj, expr[i+1], "and") if i < expr.size - 1
34
- end
35
- end
36
-
37
- this.return_variable = ret.var_name.to_sym
38
- ret
39
- end.to_s
40
- end
41
-
42
- def to_s
43
- @query
44
- end
45
-
46
- def each
47
- Neo4j._query(query).each do |r|
48
- yield r[return_variable]
49
- end
50
- end
51
- end
52
-
53
5
  # By using this class you can both specify traversals and create new relationships.
54
6
  # This object is return from the Neo4j::Core::Traversal methods.
55
7
  # @see Neo4j::Core::Traversal#outgoing
@@ -65,27 +17,14 @@ module Neo4j
65
17
  if type.nil?
66
18
  raise "Traversing all relationship in direction #{dir.inspect} not supported, only :both supported" unless dir == :both
67
19
  @td = Java::OrgNeo4jKernelImplTraversal::TraversalDescriptionImpl.new.breadth_first()
68
- elsif (dir == :both)
69
- both(type)
70
- elsif (dir == :incoming)
71
- incoming(type)
72
- elsif (dir == :outgoing)
73
- outgoing(type)
74
20
  else
75
- raise "Illegal direction #{dir.inspect}, expected :outgoing, :incoming or :both"
21
+ @type = type_to_java(type)
22
+ @dir = dir_to_java(dir)
23
+ @td = Java::OrgNeo4jKernelImplTraversal::TraversalDescriptionImpl.new.breadth_first().relationships(@type, @dir)
76
24
  end
77
25
  end
78
26
 
79
27
 
80
- def query(query_hash = nil, &block)
81
- # only one direction is supported
82
- rel_types = [@outgoing_rel_types, @incoming_rel_types, @both_rel_types].find_all { |x| !x.nil? }
83
- raise "Only one direction is allowed, outgoing:#{@outgoing_rel_types}, incoming:#{@incoming_rel_types}, @both:#{@both_rel_types}" if rel_types.count != 1
84
- start_id = @from.neo_id
85
- dir = (@outgoing_rel_types && :outgoing) || (@incoming_rel_types && :incoming) || (@both_rel_types && :both)
86
- CypherQuery.new(start_id, dir, rel_types.first, query_hash, &block)
87
- end
88
-
89
28
  # Sets traversing depth first.
90
29
  #
91
30
  # The <tt>pre_or_post</tt> parameter parameter can have two values: :pre or :post
@@ -173,19 +112,11 @@ module Neo4j
173
112
  end
174
113
 
175
114
  def to_s
176
- "NodeTraverser [from: #{@from.neo_id} depth: #{@depth}"
115
+ "NodeTraverser [from: #{@from.neo_id} depth: #{@depth} type: #{@type} dir:#{@dir}"
177
116
  end
178
117
 
179
118
 
180
119
  # Creates a new relationship between given node and self
181
- # It can create more then one relationship
182
- #
183
- # @example One outgoing relationships
184
- # node.outgoing(:foo) << other_node
185
- #
186
- # @example Two outgoing relationships
187
- # node.outgoing(:foo).outgoing(:bar) << other_node
188
- #
189
120
  # @param [Neo4j::Node] other_node the node to which we want to create a relationship
190
121
  # @return (see #new)
191
122
  def <<(other_node)
@@ -199,49 +130,25 @@ module Neo4j
199
130
  end
200
131
 
201
132
  # Creates a new relationship between self and given node.
202
- # It can create more then one relationship
203
- # This method is used by the <tt><<</tt> operator.
204
- #
205
- # @example create one relationship
206
- # node.outgoing(:bar).new(other_node, rel_props)
207
- #
208
- # @example two relationships
209
- # node.outgoing(:bar).outgoing(:foo).new(other_node, rel_props)
210
- #
211
- # @example both incoming and outgoing - two relationships
212
- # node.both(:bar).new(other_node, rel_props)
213
- #
214
- # @see #<<
215
133
  # @param [Hash] props properties of new relationship
216
134
  # @return [Neo4j::Relationship] the created relationship
217
135
  def new(other_node, props = {})
218
- @outgoing_rel_types && @outgoing_rel_types.each { |type| _new_out(other_node, type, props) }
219
- @incoming_rel_types && @incoming_rel_types.each { |type| _new_in(other_node, type, props) }
220
- @both_rel_types && @both_rel_types.each { |type| _new_both(other_node, type, props) }
221
- end
222
-
223
- # @private
224
- def _new_out(other_node, type, props)
225
- @from.create_relationship_to(other_node, type_to_java(type)).update(props)
226
- end
227
-
228
- # @private
229
- def _new_in(other_node, type, props)
230
- other_node.create_relationship_to(@from, type_to_java(type)).update(props)
231
- end
232
-
233
- # @private
234
- def _new_both(other_node, type, props)
235
- _new_out(other_node, type, props)
236
- _new_in(other_node, type, props)
136
+ case @dir
137
+ when Java::OrgNeo4jGraphdb::Direction::OUTGOING
138
+ @from.create_relationship_to(other_node, @type).update(props)
139
+ when Java::OrgNeo4jGraphdb::Direction::INCOMING
140
+ other_node.create_relationship_to(@from, @type).update(props)
141
+ else
142
+ raise "Only allowed to create outgoing or incoming relationships (not #@dir)"
143
+ end
237
144
  end
238
145
 
239
146
  # @param (see Neo4j::Core::Traversal#both)
240
147
  # @see Neo4j::Core::Traversal#both
241
148
  def both(type)
242
- @both_rel_types ||= []
243
- @both_rel_types << type
244
- _add_rel(:both, type)
149
+ @type = type_to_java(type) if type
150
+ @dir = dir_to_java(:both)
151
+ @td = @td.relationships(type_to_java(type), @dir)
245
152
  self
246
153
  end
247
154
 
@@ -258,9 +165,9 @@ module Neo4j
258
165
  # @return self
259
166
  # @see Neo4j::Core::Traversal#outgoing
260
167
  def outgoing(type)
261
- @outgoing_rel_types ||= []
262
- @outgoing_rel_types << type
263
- _add_rel(:outgoing, type)
168
+ @type = type_to_java(type) if type
169
+ @dir = dir_to_java(:outgoing)
170
+ @td = @td.relationships(type_to_java(type), @dir)
264
171
  self
265
172
  end
266
173
 
@@ -269,19 +176,12 @@ module Neo4j
269
176
  # @return self
270
177
  # @see Neo4j::Core::Traversal#incoming
271
178
  def incoming(type)
272
- @incoming_rel_types ||= []
273
- @incoming_rel_types << type
274
- _add_rel(:incoming, type)
179
+ @type = type_to_java(type) if type
180
+ @dir = dir_to_java(:incoming)
181
+ @td = @td.relationships(type_to_java(type), @dir)
275
182
  self
276
183
  end
277
184
 
278
- # @private
279
- def _add_rel(dir, type)
280
- t = type_to_java(type)
281
- d = dir_to_java(dir)
282
- @td = @td ? @td.relationships(t, d) : Java::OrgNeo4jKernelImplTraversal::TraversalDescriptionImpl.new.breadth_first().relationships(t, d)
283
- end
284
-
285
185
  # Cuts of of parts of the traversal.
286
186
  # @yield [path]
287
187
  # @yieldparam [Java::OrgNeo4jGraphdb::Path] path the path which can be used to filter nodes
@@ -328,6 +228,12 @@ module Neo4j
328
228
  self
329
229
  end
330
230
 
231
+ #def size
232
+ # s = 0
233
+ # iterator.each { |_| s += 1 }
234
+ # s
235
+ #end
236
+
331
237
  # @param [Fixnum] index the n'th node that will be return from the traversal
332
238
  def [](index)
333
239
  each_with_index { |node, i| break node if index == i }
@@ -389,7 +295,6 @@ module Neo4j
389
295
  end
390
296
 
391
297
  end
392
-
393
298
  end
394
299
  end
395
300
  end
@@ -0,0 +1,287 @@
1
+ module Neo4j
2
+
3
+ # Responsible for converting values from and to Java Neo4j and Lucene.
4
+ # You can implement your own converter by implementing the method <tt>convert?</tt>
5
+ # <tt>to_java</tt> and <tt>to_ruby</tt> in this module.
6
+ #
7
+ # There are currently three default converters that are triggered when a Time, Date or a DateTime is read or written
8
+ # if there is a type declared for the property.
9
+ #
10
+ # ==== Example
11
+ #
12
+ # Example of writing your own marshalling converter:
13
+ #
14
+ # class Foo
15
+ # include Neo4j::NodeMixin
16
+ # property :thing, :type => MyType
17
+ # end
18
+ #
19
+ # module Neo4j::TypeConverters
20
+ # class MyTypeConverter
21
+ # class << self
22
+ # def convert?(type)
23
+ # type == MyType
24
+ # end
25
+ #
26
+ # def to_java(val)
27
+ # "silly:#{val}"
28
+ # end
29
+ #
30
+ # def to_ruby(val)
31
+ # val.sub(/silly:/, '')
32
+ # end
33
+ # end
34
+ # end
35
+ # end
36
+ #
37
+ module TypeConverters
38
+
39
+ # The default converter to use if there isn't a specific converter for the type
40
+ class DefaultConverter
41
+ class << self
42
+
43
+ def to_java(value)
44
+ value
45
+ end
46
+
47
+ def to_ruby(value)
48
+ value
49
+ end
50
+ end
51
+ end
52
+
53
+
54
+ class BooleanConverter
55
+ class << self
56
+
57
+ def convert?(class_or_symbol)
58
+ :boolean == class_or_symbol
59
+ end
60
+
61
+ def to_java(value)
62
+ return nil if value.nil?
63
+ !!value && value != '0'
64
+ end
65
+
66
+ def to_ruby(value)
67
+ return nil if value.nil?
68
+ !!value && value != '0'
69
+ end
70
+ end
71
+ end
72
+
73
+ class SymbolConverter
74
+ class << self
75
+
76
+ def convert?(class_or_symbol)
77
+ :symbol == class_or_symbol || Symbol == class_or_symbol
78
+ end
79
+
80
+ def to_java(value)
81
+ return nil if value.nil?
82
+ value.to_s
83
+ end
84
+
85
+ def to_ruby(value)
86
+ return nil if value.nil?
87
+ value.to_sym
88
+ end
89
+ end
90
+ end
91
+
92
+
93
+ class StringConverter
94
+ class << self
95
+
96
+ def convert?(class_or_symbol)
97
+ [String, :string, :text].include? class_or_symbol
98
+ end
99
+
100
+ def to_java(value)
101
+ return nil if value.nil?
102
+ value.to_s
103
+ end
104
+
105
+ def to_ruby(value)
106
+ return nil if value.nil?
107
+ value.to_s
108
+ end
109
+ end
110
+ end
111
+
112
+
113
+
114
+ class FixnumConverter
115
+ class << self
116
+
117
+ def convert?(class_or_symbol)
118
+ Fixnum == class_or_symbol || :fixnum == class_or_symbol || :numeric == class_or_symbol
119
+ end
120
+
121
+ def to_java(value)
122
+ return nil if value.nil?
123
+ value.to_i
124
+ end
125
+
126
+ def to_ruby(value)
127
+ return nil if value.nil?
128
+ value.to_i
129
+ end
130
+ end
131
+ end
132
+
133
+ class FloatConverter
134
+ class << self
135
+
136
+ def convert?(clazz_or_symbol)
137
+ Float == clazz_or_symbol || :float == clazz_or_symbol
138
+ end
139
+
140
+ def to_java(value)
141
+ return nil if value.nil?
142
+ value.to_f
143
+ end
144
+
145
+ def to_ruby(value)
146
+ return nil if value.nil?
147
+ value.to_f
148
+ end
149
+ end
150
+ end
151
+
152
+ # Converts Date objects to Java long types. Must be timezone UTC.
153
+ class DateConverter
154
+ class << self
155
+
156
+ def convert?(clazz_or_symbol)
157
+ Date == clazz_or_symbol || :date == clazz_or_symbol
158
+ end
159
+
160
+ def to_java(value)
161
+ return nil if value.nil?
162
+ Time.utc(value.year, value.month, value.day).to_i
163
+ end
164
+
165
+ def to_ruby(value)
166
+ return nil if value.nil?
167
+ Time.at(value).utc.to_date
168
+ end
169
+ end
170
+ end
171
+
172
+ # Converts DateTime objects to and from Java long types. Must be timezone UTC.
173
+ class DateTimeConverter
174
+ class << self
175
+
176
+ def convert?(clazz_or_symbol)
177
+ DateTime == clazz_or_symbol || :datetime == clazz_or_symbol
178
+ end
179
+
180
+ # Converts the given DateTime (UTC) value to an Fixnum.
181
+ # Only utc times are supported !
182
+ def to_java(value)
183
+ return nil if value.nil?
184
+ if value.class == Date
185
+ Time.utc(value.year, value.month, value.day, 0, 0, 0).to_i
186
+ else
187
+ Time.utc(value.year, value.month, value.day, value.hour, value.min, value.sec).to_i
188
+ end
189
+ end
190
+
191
+ def to_ruby(value)
192
+ return nil if value.nil?
193
+ t = Time.at(value).utc
194
+ DateTime.civil(t.year, t.month, t.day, t.hour, t.min, t.sec)
195
+ end
196
+ end
197
+ end
198
+
199
+ class TimeConverter
200
+ class << self
201
+
202
+ def convert?(clazz_or_symbol)
203
+ Time == clazz_or_symbol || :time == clazz_or_symbol
204
+ end
205
+
206
+ # Converts the given DateTime (UTC) value to an Fixnum.
207
+ # Only utc times are supported !
208
+ def to_java(value)
209
+ return nil if value.nil?
210
+ if value.class == Date
211
+ Time.utc(value.year, value.month, value.day, 0, 0, 0).to_i
212
+ else
213
+ value.utc.to_i
214
+ end
215
+ end
216
+
217
+ def to_ruby(value)
218
+ return nil if value.nil?
219
+ Time.at(value).utc
220
+ end
221
+ end
222
+ end
223
+
224
+ class << self
225
+
226
+ # Mostly for testing purpose, You can use this method in order to
227
+ # add a converter while the neo4j has already started.
228
+ def converters=(converters)
229
+ @converters = converters
230
+ end
231
+
232
+ # Always returns a converter that handles to_ruby or to_java
233
+ # if +enforce_type+ is set to false then it will raise in case of unknown type
234
+ # otherwise it will return the DefaultConverter.
235
+ def converter(type = nil, enforce_type = true)
236
+ return DefaultConverter unless type
237
+ @converters ||= begin
238
+ Neo4j::TypeConverters.constants.find_all do |c|
239
+ Neo4j::TypeConverters.const_get(c).respond_to?(:convert?)
240
+ end.map do |c|
241
+ Neo4j::TypeConverters.const_get(c)
242
+ end
243
+ end
244
+ found = @converters.find {|c| c.convert?(type) }
245
+ raise "The type #{type.inspect} is unknown. Use one of #{@converters.map{|c| c.name }.join(", ")} or create a custom type converter." if !found && enforce_type
246
+ found or DefaultConverter
247
+ end
248
+
249
+ # Converts the given value to a Java type by using the registered converters.
250
+ # It just looks at the class of the given value unless an attribute name is given.
251
+ def convert(value, attribute = nil, klass = nil, enforce_type = true)
252
+ converter(attribute_type(value, attribute, klass), enforce_type).to_java(value)
253
+ end
254
+
255
+ # Converts the given property (key, value) to Java if there is a type converter for given type.
256
+ # The type must also be declared using Neo4j::NodeMixin#property property_name, :type => clazz
257
+ # If no Converter is defined for this value then it simply returns the given value.
258
+ def to_java(clazz, key, value)
259
+ type = clazz._decl_props[key.to_sym] && clazz._decl_props[key.to_sym][:type]
260
+ converter(type).to_java(value)
261
+ end
262
+
263
+ # Converts the given property (key, value) to Ruby if there is a type converter for given type.
264
+ # If no Converter is defined for this value then it simply returns the given value.
265
+ def to_ruby(clazz, key, value)
266
+ type = clazz._decl_props[key.to_sym] && clazz._decl_props[key.to_sym][:type]
267
+ converter(type).to_ruby(value)
268
+ end
269
+
270
+ private
271
+ def attribute_type(value, attribute = nil, klass = nil)
272
+ type = (attribute && klass) ? attribute_type_from_attribute_and_klass(value, attribute, klass) : nil
273
+ type || attribute_type_from_value(value)
274
+ end
275
+
276
+ def attribute_type_from_attribute_and_klass(value, attribute, klass)
277
+ if klass.respond_to?(:_decl_props)
278
+ (klass._decl_props.has_key?(attribute) && klass._decl_props[attribute][:type]) ? klass._decl_props[attribute][:type] : nil
279
+ end
280
+ end
281
+
282
+ def attribute_type_from_value(value)
283
+ value.class
284
+ end
285
+ end
286
+ end
287
+ end