neo4j-core 0.0.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 +27 -0
- data/README.rdoc +27 -0
- data/config/neo4j/config.yml +102 -0
- data/lib/db/active_tx_log +1 -0
- data/lib/db/index/lucene-store.db +0 -0
- data/lib/db/index/lucene.log.1 +0 -0
- data/lib/db/index/lucene.log.active +0 -0
- data/lib/db/lock +0 -0
- data/lib/db/messages.log +530 -0
- data/lib/db/neostore +0 -0
- data/lib/db/neostore.id +0 -0
- data/lib/db/neostore.nodestore.db +0 -0
- data/lib/db/neostore.nodestore.db.id +0 -0
- data/lib/db/neostore.propertystore.db +0 -0
- data/lib/db/neostore.propertystore.db.arrays +0 -0
- data/lib/db/neostore.propertystore.db.arrays.id +0 -0
- data/lib/db/neostore.propertystore.db.id +0 -0
- data/lib/db/neostore.propertystore.db.index +0 -0
- data/lib/db/neostore.propertystore.db.index.id +0 -0
- data/lib/db/neostore.propertystore.db.index.keys +0 -0
- data/lib/db/neostore.propertystore.db.index.keys.id +0 -0
- data/lib/db/neostore.propertystore.db.strings +0 -0
- data/lib/db/neostore.propertystore.db.strings.id +0 -0
- data/lib/db/neostore.relationshipstore.db +0 -0
- data/lib/db/neostore.relationshipstore.db.id +0 -0
- data/lib/db/neostore.relationshiptypestore.db +0 -0
- data/lib/db/neostore.relationshiptypestore.db.id +0 -0
- data/lib/db/neostore.relationshiptypestore.db.names +0 -0
- data/lib/db/neostore.relationshiptypestore.db.names.id +0 -0
- data/lib/db/nioneo_logical.log.2 +0 -0
- data/lib/db/nioneo_logical.log.active +0 -0
- data/lib/db/tm_tx_log.1 +0 -0
- data/lib/neo4j/config.rb +139 -0
- data/lib/neo4j/cypher.rb +156 -0
- data/lib/neo4j/neo4j.rb +244 -0
- data/lib/neo4j/neo4j.rb~ +214 -0
- data/lib/neo4j/node.rb +39 -0
- data/lib/neo4j/relationship.rb +61 -0
- data/lib/neo4j/transaction.rb +86 -0
- data/lib/neo4j/type_converters/type_converters.rb +287 -0
- data/lib/neo4j-core/cypher/cypher.rb +867 -0
- data/lib/neo4j-core/cypher/result_wrapper.rb +39 -0
- data/lib/neo4j-core/database.rb +191 -0
- data/lib/neo4j-core/equal/equal.rb +23 -0
- data/lib/neo4j-core/event_handler.rb +265 -0
- data/lib/neo4j-core/index/class_methods.rb +117 -0
- data/lib/neo4j-core/index/index.rb +36 -0
- data/lib/neo4j-core/index/index_config.rb +112 -0
- data/lib/neo4j-core/index/indexer.rb +243 -0
- data/lib/neo4j-core/index/indexer_registry.rb +55 -0
- data/lib/neo4j-core/index/lucene_query.rb +264 -0
- data/lib/neo4j-core/lazy_map.rb +21 -0
- data/lib/neo4j-core/node/class_methods.rb +77 -0
- data/lib/neo4j-core/node/node.rb +47 -0
- data/lib/neo4j-core/property/property.rb +94 -0
- data/lib/neo4j-core/relationship/class_methods.rb +80 -0
- data/lib/neo4j-core/relationship/relationship.rb +97 -0
- data/lib/neo4j-core/relationship_set.rb +61 -0
- data/lib/neo4j-core/rels/rels.rb +147 -0
- data/lib/neo4j-core/rels/traverser.rb +99 -0
- data/lib/neo4j-core/to_java.rb +51 -0
- data/lib/neo4j-core/traversal/evaluator.rb +36 -0
- data/lib/neo4j-core/traversal/filter_predicate.rb +30 -0
- data/lib/neo4j-core/traversal/prune_evaluator.rb +20 -0
- data/lib/neo4j-core/traversal/rel_expander.rb +35 -0
- data/lib/neo4j-core/traversal/traversal.rb +130 -0
- data/lib/neo4j-core/traversal/traverser.rb +295 -0
- data/lib/neo4j-core/version.rb +5 -0
- data/lib/neo4j-core.rb +64 -0
- data/neo4j-core.gemspec +31 -0
- metadata +145 -0
data/lib/neo4j/neo4j.rb~
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'neo4j-core/database'
|
2
|
+
|
3
|
+
# = Neo4j
|
4
|
+
#
|
5
|
+
# The Neo4j modules is used to interact with an Neo4j Database instance.
|
6
|
+
# You can for example start and stop an instance and list all the nodes that exist in the database.
|
7
|
+
#
|
8
|
+
# === Starting and Stopping Neo4j
|
9
|
+
# You don't normally need to start the Neo4j database since it will be automatically started when needed.
|
10
|
+
# Before the database is started you should configure where the database is stored, see Neo4j::Config.
|
11
|
+
#
|
12
|
+
module Neo4j
|
13
|
+
|
14
|
+
# The version of the Neo4j jar files
|
15
|
+
NEO_VERSION = Neo4j::Community::VERSION
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Start Neo4j using the default database.
|
19
|
+
# This is usally not required since the database will be started automatically when it is used.
|
20
|
+
# If the global variable $NEO4J_SERVER is defined then it will use that as the Java Graph DB. This can
|
21
|
+
# be used if you want to embed neo4j.rb and already got an instance of the Java Neo4j Database service.
|
22
|
+
#
|
23
|
+
# ==== Parameters
|
24
|
+
# config_file :: (optionally) if this is nil or not given use the Neo4j::Config, otherwise setup the Neo4j::Config file using the provided YAML configuration file.
|
25
|
+
# external_db :: (optionally) use this Java Neo4j instead of creating a new neo4j database service
|
26
|
+
def start(config_file=nil, external_db = $NEO4J_SERVER)
|
27
|
+
return if @db && @db.running?
|
28
|
+
|
29
|
+
Neo4j.config.default_file = config_file if config_file
|
30
|
+
if external_db
|
31
|
+
@db ||= Database.new
|
32
|
+
self.db.start_external_db(external_db)
|
33
|
+
else
|
34
|
+
db.start
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# Sets the Neo4j::Database instance to use
|
40
|
+
# An Neo4j::Database instance wraps both the Neo4j Database and Lucene Database.
|
41
|
+
def db=(my_db)
|
42
|
+
@db = my_db
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the database holding references to both the Neo4j Graph Database and the Lucene Database.
|
46
|
+
# Creates a new one if it does not exist, but does not start it.
|
47
|
+
def db
|
48
|
+
@db ||= Neo4j::Core::Database.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def read_only?
|
52
|
+
@db && @db.graph && @db.graph.read_only?
|
53
|
+
end
|
54
|
+
|
55
|
+
# Returns a started db instance. Starts it's not running.
|
56
|
+
# if $NEO4J_SERVER is defined then use that Java Neo4j Database service instead of creating a new one.
|
57
|
+
def started_db
|
58
|
+
start unless db.running?
|
59
|
+
db
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the current storage path of a running neo4j database.
|
63
|
+
# If the database is not running it returns nil.
|
64
|
+
def storage_path
|
65
|
+
return nil unless db.running?
|
66
|
+
db.storage_path
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the Neo4j::Config class
|
70
|
+
# Same as typing; Neo4j::Config
|
71
|
+
def config
|
72
|
+
Neo4j::Config
|
73
|
+
end
|
74
|
+
|
75
|
+
# Executes a Cypher Query
|
76
|
+
# Check the neo4j http://docs.neo4j.org/chunked/milestone/cypher-query-lang.html
|
77
|
+
# Returns an enumerable of hash values.
|
78
|
+
#
|
79
|
+
# === Usage
|
80
|
+
#
|
81
|
+
# q = Neo4j.query("START n=node({node}) RETURN n", 'node' => @node.neo_id)
|
82
|
+
# q.first['n'] #=> the @node
|
83
|
+
# q.columns.first => 'n'
|
84
|
+
#
|
85
|
+
def query(query, params = {})
|
86
|
+
engine = org.neo4j.cypher.javacompat.ExecutionEngine.new(db)
|
87
|
+
engine.execute(query, params)
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
# Returns the logger used by neo4j.
|
92
|
+
# If not specified (with Neo4j.logger=) it will use the standard Ruby logger.
|
93
|
+
# You can change standard logger threshold by configuration :logger_level.
|
94
|
+
#
|
95
|
+
# You can also specify which logger class should take care of logging with the
|
96
|
+
# :logger configuration.
|
97
|
+
#
|
98
|
+
# ==== Example
|
99
|
+
#
|
100
|
+
# Neo4j::Config[:logger] = Logger.new(STDOUT)
|
101
|
+
# Neo4j::Config[:logger_level] = Logger::ERROR
|
102
|
+
#
|
103
|
+
def logger
|
104
|
+
@logger ||= Neo4j::Config[:logger] || default_logger
|
105
|
+
end
|
106
|
+
|
107
|
+
# Sets which logger should be used.
|
108
|
+
# If this this is not called then the standard Ruby logger will be used.
|
109
|
+
def logger=(logger)
|
110
|
+
@logger = logger
|
111
|
+
end
|
112
|
+
|
113
|
+
def default_logger #:nodoc:
|
114
|
+
require 'logger'
|
115
|
+
logger = Logger.new(STDOUT)
|
116
|
+
logger.sev_threshold = Neo4j::Config[:logger_level] || Logger::INFO
|
117
|
+
logger
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
# Returns an unstarted db instance
|
122
|
+
#
|
123
|
+
# This is typically used for configuring the database, which must sometimes
|
124
|
+
# be done before the database is started
|
125
|
+
# if the database was already started an exception will be raised
|
126
|
+
def unstarted_db
|
127
|
+
@db ||= Database.new
|
128
|
+
raise "database was already started" if @db.running?
|
129
|
+
@db
|
130
|
+
end
|
131
|
+
|
132
|
+
# returns true if the database is running
|
133
|
+
def running?
|
134
|
+
@db && @db.running?
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
# Stops this database
|
139
|
+
# There are Ruby hooks that will do this automatically for you.
|
140
|
+
#
|
141
|
+
def shutdown(this_db = @db)
|
142
|
+
this_db.shutdown if this_db
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
# Returns the default reference node, which is a "starting point" in the node space.
|
147
|
+
#
|
148
|
+
def default_ref_node(this_db = self.started_db)
|
149
|
+
this_db.graph.reference_node
|
150
|
+
end
|
151
|
+
|
152
|
+
# Returns the reference node, which is a "starting point" in the node space.
|
153
|
+
# In case the ref_node has been assigned via the threadlocal_ref_node method, then that node will be returned instead.
|
154
|
+
#
|
155
|
+
# Usually, a client attaches relationships to this node that leads into various parts of the node space.
|
156
|
+
# For more information about common node space organizational patterns, see the design guide at http://wiki.neo4j.org/content/Design_Guide
|
157
|
+
#
|
158
|
+
def ref_node(this_db = self.started_db)
|
159
|
+
return Thread.current[:local_ref_node] if Thread.current[:local_ref_node]
|
160
|
+
default_ref_node(this_db)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Changes the reference node on a threadlocal basis.
|
164
|
+
# This can be used to achieve multitenancy. All new entities will be attached to the new ref_node,
|
165
|
+
# which effectively partitions the graph, and hence scopes traversals.
|
166
|
+
def threadlocal_ref_node=(reference_node)
|
167
|
+
Thread.current[:local_ref_node] = reference_node.nil? ? nil : reference_node._java_node
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns a Management JMX Bean.
|
171
|
+
#
|
172
|
+
# Notice that this information is also provided by the jconsole Java tool, check http://wiki.neo4j.org/content/Monitoring_and_Deployment
|
173
|
+
# and http://docs.neo4j.org/chunked/milestone/operations-monitoring.html
|
174
|
+
#
|
175
|
+
# By default it returns the Primitivies JMX Bean that can be used to find number of nodes in use.
|
176
|
+
#
|
177
|
+
# ==== Example Neo4j Primititives
|
178
|
+
#
|
179
|
+
# Neo4j.management.get_number_of_node_ids_in_use
|
180
|
+
# Neo4j.management.getNumberOfPropertyIdsInUse
|
181
|
+
# Neo4j.management.getNumberOfRelationshipIdsInUse
|
182
|
+
# Neo4j.management.get_number_of_relationship_type_ids_in_use
|
183
|
+
#
|
184
|
+
# ==== Example Neo4j HA Cluster Info
|
185
|
+
#
|
186
|
+
# Neo4j.management(org.neo4j.management.HighAvailability).isMaster
|
187
|
+
#
|
188
|
+
# ==== Arguments
|
189
|
+
#
|
190
|
+
# jmx_clazz :: http://api.neo4j.org/current/org/neo4j/management/package-summary.html
|
191
|
+
# this_db :: default currently runnig instance or a newly started neo4j db instance
|
192
|
+
#
|
193
|
+
def management(jmx_clazz = org.neo4j.jmx.Primitives, this_db = self.started_db)
|
194
|
+
this_db.management(jmx_clazz)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Returns an Enumerable object for all nodes in the database
|
198
|
+
def all_nodes(this_db = self.started_db)
|
199
|
+
Enumerator.new(this_db, :each_node)
|
200
|
+
end
|
201
|
+
|
202
|
+
# Same as #all_nodes but does not return wrapped nodes but instead raw java node objects.
|
203
|
+
def _all_nodes(this_db = self.started_db)
|
204
|
+
Enumerator.new(this_db, :_each_node)
|
205
|
+
end
|
206
|
+
|
207
|
+
# Returns the Neo4j::EventHandler
|
208
|
+
#
|
209
|
+
def event_handler(this_db = db)
|
210
|
+
this_db.event_handler
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
end
|
data/lib/neo4j/node.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Neo4j
|
2
|
+
# A node in the graph with properties and relationships to other entities.
|
3
|
+
# Along with relationships, nodes are the core building blocks of the Neo4j data representation model.
|
4
|
+
# Node has three major groups of operations: operations that deal with relationships, operations that deal with properties and operations that traverse the node space.
|
5
|
+
# The property operations give access to the key-value property pairs.
|
6
|
+
# Property keys are always strings. Valid property value types are the primitives (<tt>String</tt>, <tt>Fixnum</tt>, <tt>Float</tt>, <tt>Boolean</tt>), and arrays of those primitives.
|
7
|
+
#
|
8
|
+
# The Neo4j::Node#new method does not return a new Ruby instance (!). Instead it will call the Neo4j Java API which will return a
|
9
|
+
# *org.neo4j.kernel.impl.core.NodeProxy* object. This java object includes the same mixin as this class. The #class method on the java object
|
10
|
+
# returns Neo4j::Node in order to make it feel like an ordinary Ruby object.
|
11
|
+
#
|
12
|
+
class Node
|
13
|
+
extend Neo4j::Core::Node::ClassMethods
|
14
|
+
|
15
|
+
include Neo4j::Core::Property
|
16
|
+
include Neo4j::Core::Rels
|
17
|
+
include Neo4j::Core::Traversal
|
18
|
+
include Neo4j::Core::Equal
|
19
|
+
include Neo4j::Core::Node
|
20
|
+
|
21
|
+
class << self
|
22
|
+
|
23
|
+
|
24
|
+
# This method is used to extend a Java Neo4j class so that it includes the same mixins as this class.
|
25
|
+
def extend_java_class(java_clazz)
|
26
|
+
java_clazz.class_eval do
|
27
|
+
include Neo4j::Core::Property
|
28
|
+
include Neo4j::Core::Rels
|
29
|
+
include Neo4j::Core::Traversal
|
30
|
+
include Neo4j::Core::Equal
|
31
|
+
include Neo4j::Core::Node
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Neo4j::Node.extend_java_class(Java::OrgNeo4jKernelImplCore::NodeProxy)
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Neo4j
|
2
|
+
|
3
|
+
|
4
|
+
# A relationship between two nodes in the graph. A relationship has a start node, an end node and a type.
|
5
|
+
# You can attach properties to relationships like Neo4j::Node.
|
6
|
+
#
|
7
|
+
# The fact that the relationship API gives meaning to start and end nodes implicitly means that all relationships have a direction.
|
8
|
+
# In the example above, rel would be directed from node to otherNode.
|
9
|
+
# A relationship's start node and end node and their relation to outgoing and incoming are defined so that the assertions in the following code are true:
|
10
|
+
#
|
11
|
+
# Furthermore, Neo4j guarantees that a relationship is never "hanging freely,"
|
12
|
+
# i.e. start_node, end_node and other_node are guaranteed to always return valid, non-nil nodes.
|
13
|
+
#
|
14
|
+
# === Wrapping
|
15
|
+
#
|
16
|
+
# Notice that the Neo4j::Relationship.new does not create a Ruby object. Instead, it returns a Java
|
17
|
+
# Java::OrgNeo4jGraphdb::Relationship object which has been modified to feel more rubyish (like Neo4j::Node).
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# a = Neo4j::Node.new
|
21
|
+
# b = Neo4j::Node.new
|
22
|
+
# rel = Neo4j::Relationship.new(:friends, a, b)
|
23
|
+
# # Now we have: (a) --- friends ---> (b)
|
24
|
+
#
|
25
|
+
# rel.start_node # => a
|
26
|
+
# rel.end_node # => b
|
27
|
+
#
|
28
|
+
# @example using the << operator on the Neo4j::Node relationship methods
|
29
|
+
#
|
30
|
+
# node.outgoing(:friends) << other_node << yet_another_node
|
31
|
+
#
|
32
|
+
# @see http://api.neo4j.org/current/org/neo4j/graphdb/Relationship.html
|
33
|
+
#
|
34
|
+
class Relationship
|
35
|
+
extend Neo4j::Core::Relationship::ClassMethods
|
36
|
+
include Neo4j::Core::Property
|
37
|
+
include Neo4j::Core::Equal
|
38
|
+
include Neo4j::Core::Relationship
|
39
|
+
|
40
|
+
# (see Neo4j::Core::Relationship::ClassMethods#new)
|
41
|
+
def initialize(rel_type, start_node, end_node, props={})
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
class << self
|
46
|
+
def extend_java_class(java_clazz) #:nodoc:
|
47
|
+
java_clazz.class_eval do
|
48
|
+
include Neo4j::Core::Property
|
49
|
+
include Neo4j::Core::Equal
|
50
|
+
include Neo4j::Core::Relationship
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
Neo4j::Relationship.extend_java_class(Java::OrgNeo4jKernelImplCore::RelationshipProxy)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Neo4j
|
2
|
+
#
|
3
|
+
# All modifying operations that work with the node space must be wrapped in a transaction. Transactions are thread confined.
|
4
|
+
# Neo4j does not implement true nested transaction, instead it uses flat nested transactions
|
5
|
+
#
|
6
|
+
# @see http://docs.neo4j.org/chunked/milestone/transactions.html
|
7
|
+
class Transaction
|
8
|
+
|
9
|
+
# Acquires a write lock for entity for this transaction. The lock (returned from this method) can be released manually, but if not it's released automatically when the transaction finishes.
|
10
|
+
# There is no implementation for this here because it's an java method
|
11
|
+
#
|
12
|
+
# @param [Neo4j::Relationship, Neo4j::Node] java_entity the entity to acquire a lock for. If another transaction currently holds a write lock to that entity this call will wait until it's released.
|
13
|
+
# @return [Java::OrgNeo4jGraphdb::Lock] a Lock which optionally can be used to release this lock earlier than when the transaction finishes. If not released (with Lock.release() it's going to be released with the transaction finishes.
|
14
|
+
# @see http://api.neo4j.org/current/org/neo4j/graphdb/Transaction.html#acquireWriteLock(Java::OrgNeo4jGraphdb::PropertyContainer)
|
15
|
+
# @see http://api.neo4j.org/current/org/neo4j/graphdb/Lock.html
|
16
|
+
def acquire_write_lock(java_entity)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Acquires a read lock for entity for this transaction. The lock (returned from this method) can be released manually, but if not it's released automatically when the transaction finishes.
|
20
|
+
# There is no implementation for this here because it's an java method
|
21
|
+
# @param [Neo4j::Relationship, Neo4j::Node] java_entity the entity to acquire a lock for. If another transaction currently hold a write lock to that entity this call will wait until it's released.
|
22
|
+
# @return [Java::OrgNeo4jGraphdb::Lock] a Lock which optionally can be used to release this lock earlier than when the transaction finishes. If not released (with Lock.release() it's going to be released with the transaction finishes.
|
23
|
+
# @see http://api.neo4j.org/current/org/neo4j/graphdb/Transaction.html#acquireReadLock(Java::OrgNeo4jGraphdb::PropertyContainer)
|
24
|
+
# @see http://api.neo4j.org/current/org/neo4j/graphdb/Lock.html
|
25
|
+
def acquire_read_lock(java_entity)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Starts a new Neo4j Transaction
|
29
|
+
# @return [Java::OrgNeo4jGraphdb::Transaction] a Java Neo4j Transaction object
|
30
|
+
# @see http://api.neo4j.org/current/org/neo4j/graphdb/Transaction.html
|
31
|
+
#
|
32
|
+
# @example
|
33
|
+
# tx = Neo4j::Transaction.new
|
34
|
+
# # modify something
|
35
|
+
# tx.success
|
36
|
+
# tx.finish
|
37
|
+
def self.new(instance = Neo4j.started_db)
|
38
|
+
instance.begin_tx
|
39
|
+
end
|
40
|
+
|
41
|
+
# Runs a block in a Neo4j transaction
|
42
|
+
#
|
43
|
+
# Many operations on neo requires an transaction. You will get much better performance if
|
44
|
+
# one transaction is wrapped around several neo operation instead of running one transaction per
|
45
|
+
# neo operation.
|
46
|
+
# If one transaction is already running then a 'placebo' transaction will be created.
|
47
|
+
# Performing a finish on a placebo transaction will not finish the 'real' transaction.
|
48
|
+
#
|
49
|
+
# If an exception occurs inside the block the transaction will rollback automatically.
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
#
|
53
|
+
# Neo4j::Transaction.run { node = PersonNode.new }
|
54
|
+
#
|
55
|
+
# @example access to the transaction and rollback
|
56
|
+
#
|
57
|
+
# Neo4j::Transaction.run do |t|
|
58
|
+
# # something failed
|
59
|
+
# t.failure # will cause a rollback
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# @yield the block which should be run under one transaction
|
63
|
+
# @yieldparam [Neo4j::Transaction]
|
64
|
+
# @return The value of the evaluated provided block
|
65
|
+
#
|
66
|
+
def self.run
|
67
|
+
raise ArgumentError.new("Expected a block to run in Transaction.run") unless block_given?
|
68
|
+
|
69
|
+
begin
|
70
|
+
tx = Neo4j::Transaction.new
|
71
|
+
ret = yield tx
|
72
|
+
tx.success
|
73
|
+
rescue Exception => e
|
74
|
+
if Neo4j::Config[:debug_java] && e.respond_to?(:cause)
|
75
|
+
puts "Java Exception in a transaction, cause: #{e.cause}"
|
76
|
+
e.cause.print_stack_trace
|
77
|
+
end
|
78
|
+
tx.failure unless tx.nil?
|
79
|
+
raise
|
80
|
+
ensure
|
81
|
+
tx.finish unless tx.nil?
|
82
|
+
end
|
83
|
+
ret
|
84
|
+
end
|
85
|
+
end
|
86
|
+
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
|