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.
- data/Gemfile +2 -2
- data/README.rdoc +12 -192
- data/lib/neo4j-core.rb +3 -19
- data/lib/neo4j-core/database.rb +5 -4
- data/lib/neo4j-core/event_handler.rb +1 -1
- data/lib/neo4j-core/index/class_methods.rb +41 -27
- data/lib/neo4j-core/index/index.rb +4 -3
- data/lib/neo4j-core/index/index_config.rb +23 -30
- data/lib/neo4j-core/index/indexer.rb +53 -65
- data/lib/neo4j-core/index/indexer_registry.rb +2 -2
- data/lib/neo4j-core/index/lucene_query.rb +42 -53
- data/lib/neo4j-core/node/class_methods.rb +4 -4
- data/lib/neo4j-core/node/node.rb +8 -1
- data/lib/neo4j-core/property/property.rb +3 -1
- data/lib/neo4j-core/relationship/relationship.rb +10 -8
- data/lib/neo4j-core/rels/rels.rb +4 -9
- data/lib/neo4j-core/rels/traverser.rb +27 -13
- data/lib/neo4j-core/traversal/prune_evaluator.rb +2 -2
- data/lib/neo4j-core/traversal/traverser.rb +27 -122
- data/lib/neo4j-core/type_converters/type_converters.rb +287 -0
- data/lib/neo4j-core/version.rb +1 -1
- data/lib/neo4j-core/version.rb~ +3 -0
- data/lib/neo4j/config.rb +6 -3
- data/lib/neo4j/neo4j.rb +22 -51
- data/lib/neo4j/node.rb +0 -27
- data/lib/neo4j/relationship.rb +0 -25
- data/lib/test.rb +27 -0
- data/neo4j-core.gemspec +2 -2
- metadata +11 -17
- data/lib/neo4j-core/cypher/cypher.rb +0 -969
- data/lib/neo4j-core/cypher/result_wrapper.rb +0 -48
- data/lib/neo4j-core/hash_with_indifferent_access.rb +0 -165
- data/lib/neo4j-core/index/unique_factory.rb +0 -54
- data/lib/neo4j-core/property/java.rb +0 -59
- data/lib/neo4j-core/wrapper/class_methods.rb +0 -22
- data/lib/neo4j-core/wrapper/wrapper.rb +0 -20
- data/lib/neo4j/algo.rb +0 -300
- 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
|
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
|
-
# @
|
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
|
data/lib/neo4j-core/node/node.rb
CHANGED
@@ -31,7 +31,14 @@ module Neo4j
|
|
31
31
|
Neo4j::Node.exist?(self)
|
32
32
|
end
|
33
33
|
|
34
|
-
#
|
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
|
-
|
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
|
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 # =>
|
83
|
-
# @return [
|
84
|
+
# a.rels.first.rel_type # => 'friends'
|
85
|
+
# @return [String] the type of the relationship
|
84
86
|
def rel_type
|
85
|
-
getType().name()
|
87
|
+
getType().name()
|
86
88
|
end
|
87
89
|
|
88
90
|
def class
|
data/lib/neo4j-core/rels/rels.rb
CHANGED
@@ -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
|
-
|
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))
|
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))
|
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))
|
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
|
-
|
30
|
-
|
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 #
|
46
|
-
def
|
47
|
-
if @
|
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 == @
|
66
|
+
rel._end_node == @to_other
|
51
67
|
elsif @dir == :incoming
|
52
|
-
rel._start_node == @
|
68
|
+
rel._start_node == @to_other
|
53
69
|
else
|
54
|
-
rel._start_node == @
|
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]
|
75
|
+
# @param [Neo4j::Node] to_other a node or an object that implements the Neo4j::Core::Equal mixin
|
60
76
|
# @return self
|
61
|
-
def
|
62
|
-
@
|
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
|
-
|
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
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
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
|
-
@
|
243
|
-
@
|
244
|
-
|
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
|
-
@
|
262
|
-
@
|
263
|
-
|
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
|
-
@
|
273
|
-
@
|
274
|
-
|
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
|