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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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