neo4j-core 0.0.1-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,77 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Core
|
3
|
+
module Node
|
4
|
+
module ClassMethods
|
5
|
+
# Returns a new neo4j Node.
|
6
|
+
# The return node is actually an Java object of type Java::OrgNeo4jGraphdb::Node java object
|
7
|
+
# which has been extended (see the included mixins for Neo4j::Node).
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# The created node will have a unique id - Neo4j::Property#neo_id
|
11
|
+
#
|
12
|
+
# @param [Hash, Array] args either an hash of properties or an array where the first item is the database to be used and the second item is the properties
|
13
|
+
# @return [Java::OrgNeo4jGraphdb::Node] the java node which implements the Neo4j::Node mixins
|
14
|
+
#
|
15
|
+
# @example using default database
|
16
|
+
#
|
17
|
+
# Neo4j::Transaction.run do
|
18
|
+
# Neo4j::Node.new
|
19
|
+
# Neo4j::Node.new :name => 'foo', :age => 100
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# @example using a different database
|
23
|
+
#
|
24
|
+
# Neo4j::Node.new({:name => 'foo', :age => 100}, my_db)
|
25
|
+
def new(*args)
|
26
|
+
# the first argument can be an hash of properties to set
|
27
|
+
props = args[0].respond_to?(:each_pair) && args[0]
|
28
|
+
|
29
|
+
# a db instance can be given, is the first argument if that was not a hash, or otherwise the second
|
30
|
+
db = (!props && args[0]) || args[1] || Neo4j.started_db
|
31
|
+
|
32
|
+
node = db.graph.create_node
|
33
|
+
props.each_pair { |k, v| node[k]= v } if props
|
34
|
+
node
|
35
|
+
end
|
36
|
+
|
37
|
+
# create is the same as new
|
38
|
+
alias_method :create, :new
|
39
|
+
|
40
|
+
|
41
|
+
# Same as load but does not return the node as a wrapped Ruby object.
|
42
|
+
#
|
43
|
+
def _load(node_id, db = Neo4j.started_db)
|
44
|
+
return nil if node_id.nil?
|
45
|
+
db.graph.get_node_by_id(node_id.to_i)
|
46
|
+
rescue Java::OrgNeo4jGraphdb.NotFoundException
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# Checks if the given entity node or entity id (Neo4j::Node#neo_id) exists in the database.
|
52
|
+
# @return [true, false] if exist
|
53
|
+
def exist?(entity_or_entity_id, db = Neo4j.started_db)
|
54
|
+
id = entity_or_entity_id.kind_of?(Fixnum) ? entity_or_entity_id : entity_or_entity_id.id
|
55
|
+
node = _load(id, db)
|
56
|
+
return false unless node
|
57
|
+
node.has_property?('a')
|
58
|
+
true
|
59
|
+
rescue java.lang.IllegalStateException
|
60
|
+
nil # the node has been deleted
|
61
|
+
end
|
62
|
+
|
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 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.
|
67
|
+
#
|
68
|
+
# @return [Object, nil] If the node does not exist it will return nil otherwise the loaded node or wrapped node.
|
69
|
+
def load(node_id, db = Neo4j.started_db)
|
70
|
+
node = _load(node_id, db)
|
71
|
+
node && node.wrapper
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Neo4j
|
2
|
+
|
3
|
+
module Core
|
4
|
+
module Node
|
5
|
+
|
6
|
+
# Delete the node and all its relationship.
|
7
|
+
#
|
8
|
+
# It might raise an exception if this method was called without a Transaction,
|
9
|
+
# or if it failed to delete the node (it maybe was already deleted).
|
10
|
+
#
|
11
|
+
# If this method raise an exception you may also get an exception when the transaction finish.
|
12
|
+
# This method is defined in the Java::OrgNeo4jKernel::impl.core.NodeProxy which is return by Neo4j::Node.new
|
13
|
+
#
|
14
|
+
# @return nil or raise an exception
|
15
|
+
def del
|
16
|
+
_rels.each { |r| r.del }
|
17
|
+
delete
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
# This method can be used to access the none wrapped neo4j node/relationship java object.
|
22
|
+
# Notice that this method is defined in the Java::OrgNeo4jKernel::impl.core.NodeProxy or RelationshipProxy which is return by Neo4j::Node.new
|
23
|
+
# @return the java node/relationship object representing this object unless it is already the java object.
|
24
|
+
def _java_node
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
# Same as Neo4j::Node#exist? or Neo4j::Relationship#exist?
|
29
|
+
# @return [true, false] if the node exists in the database
|
30
|
+
def exist?
|
31
|
+
Neo4j::Node.exist?(self)
|
32
|
+
end
|
33
|
+
|
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
|
+
|
42
|
+
def class
|
43
|
+
Neo4j::Node
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Core
|
3
|
+
module Property
|
4
|
+
|
5
|
+
# @return [Hash] all properties plus the id of the node with the key <tt>_neo_id</tt>
|
6
|
+
def props
|
7
|
+
ret = {"_neo_id" => neo_id}
|
8
|
+
iter = get_property_keys.iterator
|
9
|
+
while (iter.hasNext) do
|
10
|
+
key = iter.next
|
11
|
+
ret[key] = get_property(key)
|
12
|
+
end
|
13
|
+
ret
|
14
|
+
end
|
15
|
+
|
16
|
+
# Ids are garbage collected over time so they are only guaranteed to be unique during a specific time span:
|
17
|
+
# if the node is deleted, it's likely that a new node at some point will get the old id. Note:
|
18
|
+
# this makes node ids brittle as public APIs.
|
19
|
+
# @return [Fixnum] the unique id of this node.
|
20
|
+
def neo_id
|
21
|
+
getId
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param [#to_s] the property we want to check if it exist.
|
25
|
+
# @return [true false] true if the given key exist as a property.
|
26
|
+
def property?(key)
|
27
|
+
has_property?(key.to_s)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Updates this node/relationship's properties by using the provided struct/hash.
|
31
|
+
# If the option <code>{:strict => true}</code> is given, any properties present on
|
32
|
+
# the node but not present in the hash will be removed from the node.
|
33
|
+
#
|
34
|
+
# @param [Hash, :each_pair] struct_or_hash the key and value to be set
|
35
|
+
# @param [Hash] options further options defining the context of the update
|
36
|
+
# @option options [Boolean] :strict any properties present on the node but not present in the hash will be removed from the node if true
|
37
|
+
# @return self
|
38
|
+
def update(struct_or_hash, options={})
|
39
|
+
strict = options[:strict]
|
40
|
+
keys_to_delete = props.keys - %w(_neo_id _classname) if strict
|
41
|
+
struct_or_hash.each_pair do |key, value|
|
42
|
+
next if key.to_s[0..0] == '_'
|
43
|
+
# do not allow special properties to be mass assigned
|
44
|
+
keys_to_delete.delete(key.to_s) if strict
|
45
|
+
self[key] = value
|
46
|
+
end
|
47
|
+
keys_to_delete.each { |key| remove_property(key) } if strict
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
# @return the value of the given key or nil if the property does not exist.
|
53
|
+
def [](key)
|
54
|
+
return unless property?(key)
|
55
|
+
val = get_property(key.to_s)
|
56
|
+
val.class.superclass == ArrayJavaProxy ? val.to_a : val
|
57
|
+
end
|
58
|
+
|
59
|
+
# Sets the property of this node.
|
60
|
+
# Property keys are always strings. Valid property value types are the primitives(<tt>String</tt>, <tt>Fixnum</tt>, <tt>Float</tt>, <tt>FalseClass</tt>, <tt>TrueClass</tt>) or array of those primitives.
|
61
|
+
#
|
62
|
+
# ==== Gotchas
|
63
|
+
# * Values in the array must be of the same type.
|
64
|
+
# * You can *not* delete or add one item in the array (e.g. person.phones.delete('123')) but instead you must create a new array instead.
|
65
|
+
#
|
66
|
+
# @param [String, Symbol] key of the property to set
|
67
|
+
# @param [String,Fixnum,Float,true,false, Array] value to set
|
68
|
+
def []=(key, value)
|
69
|
+
k = key.to_s
|
70
|
+
if value.nil?
|
71
|
+
remove_property(k)
|
72
|
+
elsif (Array === value)
|
73
|
+
case value[0]
|
74
|
+
when NilClass
|
75
|
+
set_property(k, [].to_java(:string))
|
76
|
+
when String
|
77
|
+
set_property(k, value.to_java(:string))
|
78
|
+
when Float
|
79
|
+
set_property(k, value.to_java(:double))
|
80
|
+
when FalseClass, TrueClass
|
81
|
+
set_property(k, value.to_java(:boolean))
|
82
|
+
when Fixnum
|
83
|
+
set_property(k, value.to_java(:long))
|
84
|
+
else
|
85
|
+
raise "Not allowed to store array with value #{value[0]} type #{value[0].class}"
|
86
|
+
end
|
87
|
+
else
|
88
|
+
set_property(k, value)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Core
|
3
|
+
module Relationship
|
4
|
+
module ClassMethods
|
5
|
+
|
6
|
+
# Returns a Java::OrgNeo4jGraphdb::Relationship java object which include the Neo4j::Relationship mixins.
|
7
|
+
# Will trigger a event that the relationship was created.
|
8
|
+
#
|
9
|
+
# @param [String, Symbol] type of relationship
|
10
|
+
# @param [#_java_node] from_node the start node of this relationship
|
11
|
+
# @param [#_java_node] end_node the end node of this relationship
|
12
|
+
# @param [Hash] props optional properties for the created relationship
|
13
|
+
#
|
14
|
+
# @return [Neo4j::Relationship] which is really a Java::OrgNeo4jGraphdb::Relationship java object including the Neo4j::Relationship mixins
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
#
|
18
|
+
# Neo4j::Relationship.new :friend, node1, node2, :since => '2001-01-02', :status => 'okey'
|
19
|
+
#
|
20
|
+
def new(type, start_node, end_node, props=nil)
|
21
|
+
java_type = ToJava.type_to_java(type)
|
22
|
+
rel = start_node._java_node.create_relationship_to(end_node._java_node, java_type)
|
23
|
+
props.each_pair { |k, v| rel[k] = v } if props
|
24
|
+
rel
|
25
|
+
end
|
26
|
+
|
27
|
+
# create is the same as new
|
28
|
+
alias_method :create, :new
|
29
|
+
|
30
|
+
# Loads a relationship or wrapped relationship given a native java relationship or an id.
|
31
|
+
# If there is a Ruby wrapper for the node then it will create a Ruby object that will
|
32
|
+
# wrap the java node (see Neo4j::RelationshipMixin).
|
33
|
+
# Notice that it can load the node even if it has been deleted in the same transaction, see #exist?
|
34
|
+
#
|
35
|
+
# @see #_load
|
36
|
+
# @see #exist?
|
37
|
+
# @return the wrapper for the relationship or nil
|
38
|
+
def load(rel_id, db = Neo4j.started_db)
|
39
|
+
rel = _load(rel_id, db)
|
40
|
+
return nil if rel.nil?
|
41
|
+
rel.wrapper
|
42
|
+
end
|
43
|
+
|
44
|
+
# Same as load but does not return the node as a wrapped Ruby object.
|
45
|
+
# @see #load
|
46
|
+
def _load(rel_id, db = Neo4j.started_db)
|
47
|
+
return nil if rel_id.nil?
|
48
|
+
rel = db.graph.get_relationship_by_id(rel_id.to_i)
|
49
|
+
# TODO
|
50
|
+
rel
|
51
|
+
rescue Java::OrgNeo4jGraphdb::NotFoundException
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
# Checks if the given node or entity id (Neo4j::Relationship#neo_id) exists in the database.
|
56
|
+
# @return [true, false] if exist
|
57
|
+
def exist?(entity_or_entity_id, db = Neo4j.started_db)
|
58
|
+
id = entity_or_entity_id.kind_of?(Fixnum) ? entity_or_entity_id : entity_or_entity_id.id
|
59
|
+
entity = _load(id, db)
|
60
|
+
return false unless entity
|
61
|
+
entity.hasProperty('_classname') # since we want a IllegalStateException which is otherwise not triggered
|
62
|
+
true
|
63
|
+
rescue java.lang.IllegalStateException
|
64
|
+
nil # the node has been deleted
|
65
|
+
end
|
66
|
+
|
67
|
+
# Loads a relationship or wrapped relationship given a native java relationship or an id.
|
68
|
+
# If there is a Ruby wrapper for the relationship then it will create a Ruby object that will
|
69
|
+
# wrap the java node (see Neo4j::RelationshipMixin).
|
70
|
+
# To implement a wrapper you must implement a wrapper class method in the Neo4j::Node or Neo4j::Relationship.
|
71
|
+
#
|
72
|
+
# @return [Object, nil] If the node does not exist it will return nil otherwise the loaded node or wrapped node.
|
73
|
+
def load(node_id, db = Neo4j.started_db)
|
74
|
+
node = _load(node_id, db)
|
75
|
+
node && node.wrapper
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Core
|
3
|
+
module Relationship
|
4
|
+
|
5
|
+
# Same as Java::OrgNeo4jGraphdb::Relationship#getEndNode
|
6
|
+
def _end_node
|
7
|
+
get_end_node
|
8
|
+
end
|
9
|
+
|
10
|
+
# Same as Java::OrgNeo4jGraphdb::Relationship#getStartNode
|
11
|
+
def _start_node
|
12
|
+
get_start_node
|
13
|
+
end
|
14
|
+
|
15
|
+
# Same as Java::OrgNeo4jGraphdb::Relationship#getOtherNode
|
16
|
+
def _other_node(node)
|
17
|
+
get_other_node(node)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Deletes the relationship between the start and end node
|
21
|
+
# May raise an exception if delete was unsuccessful.
|
22
|
+
#
|
23
|
+
# @return [nil]
|
24
|
+
def del
|
25
|
+
delete
|
26
|
+
end
|
27
|
+
|
28
|
+
# Same as Java::OrgNeo4jGraphdb::Relationship#getEndNode but returns the wrapper for it (if it exist)
|
29
|
+
# @see Neo4j::Node#wrapper
|
30
|
+
def end_node
|
31
|
+
_end_node.wrapper
|
32
|
+
end
|
33
|
+
|
34
|
+
# Same as Java::OrgNeo4jGraphdb::Relationship#getStartNode but returns the wrapper for it (if it exist)
|
35
|
+
# @see Neo4j::Node#wrapper
|
36
|
+
def start_node
|
37
|
+
_start_node.wrapper
|
38
|
+
end
|
39
|
+
|
40
|
+
# A convenience operation that, given a node that is attached to this relationship, returns the other node.
|
41
|
+
# For example if node is a start node, the end node will be returned, and vice versa.
|
42
|
+
# This is a very convenient operation when you're manually traversing the node space by invoking one of the #rels
|
43
|
+
# method on a node. For example, to get the node "at the other end" of a relationship, use the following:
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# end_node = node.rels.first.other_node(node)
|
47
|
+
#
|
48
|
+
# @raise This operation will throw a runtime exception if node is neither this relationship's start node nor its end node.
|
49
|
+
#
|
50
|
+
# @param [Neo4j::Node] node the node that we don't want to return
|
51
|
+
# @return [Neo4j::Node] the other node wrapper
|
52
|
+
def other_node(node)
|
53
|
+
_other_node(node._java_node).wrapper
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# same as #_java_rel
|
58
|
+
# Used so that we have same method for both relationship and nodes
|
59
|
+
def wrapped_entity
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return self
|
64
|
+
def _java_rel
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [true, false] if the relationship exists
|
69
|
+
def exist?
|
70
|
+
Neo4j::Relationship.exist?(self)
|
71
|
+
end
|
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
|
+
|
79
|
+
# Returns the relationship name
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
# a = Neo4j::Node.new
|
83
|
+
# a.outgoing(:friends) << Neo4j::Node.new
|
84
|
+
# a.rels.first.rel_type # => 'friends'
|
85
|
+
# @return [String] the type of the relationship
|
86
|
+
def rel_type
|
87
|
+
getType().name()
|
88
|
+
end
|
89
|
+
|
90
|
+
def class
|
91
|
+
Neo4j::Relationship
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Core
|
3
|
+
# == Represents a set of relationships.
|
4
|
+
# See Neo4j::EventHandler
|
5
|
+
class RelationshipSet
|
6
|
+
def initialize(size=0)
|
7
|
+
@relationship_type_set = java.util.HashSet.new(size)
|
8
|
+
@relationship_set = java.util.HashSet.new(size)
|
9
|
+
@relationship_map = java.util.HashMap.new(size)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Adds a relationship to the set
|
13
|
+
def add(rel)
|
14
|
+
@relationship_type_set.add(RelationshipSetEntry.new(rel.getEndNode().getId(), rel.rel_type))
|
15
|
+
relationships(rel.getEndNode().getId()) << rel
|
16
|
+
@relationship_set.add(rel.getId)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns a collection of relationships where the node with the specified end node id is the end node.
|
20
|
+
def relationships(end_node_id)
|
21
|
+
@relationship_map.get(end_node_id) || add_list(end_node_id)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns true if the specified relationship is in the set
|
25
|
+
def contains_rel?(rel)
|
26
|
+
@relationship_set.contains(rel.getId)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns true if a relationship with the specified end_node_id and relationship_type is present in the set.
|
30
|
+
def contains?(end_node_id, relationship_type)
|
31
|
+
@relationship_type_set.contains(RelationshipSetEntry.new(end_node_id, relationship_type))
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
def add_list(node_id)
|
36
|
+
@relationship_map.put(node_id, [])
|
37
|
+
@relationship_map.get(node_id)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class RelationshipSetEntry
|
42
|
+
attr_accessor :nodeid, :relationship_type
|
43
|
+
|
44
|
+
def initialize(nodeid, relationship_type)
|
45
|
+
@nodeid, @relationship_type = nodeid.to_s, relationship_type.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def ==(o)
|
49
|
+
eql?(o)
|
50
|
+
end
|
51
|
+
|
52
|
+
def eql?(other)
|
53
|
+
@nodeid == other.nodeid && @relationship_type == other.relationship_type
|
54
|
+
end
|
55
|
+
|
56
|
+
def hash
|
57
|
+
3 * @nodeid.hash + @relationship_type.hash
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Core
|
3
|
+
# Contains methods for traversing relationship object of depth one from one node.
|
4
|
+
module Rels
|
5
|
+
# Returns the only node of a given type and direction that is attached to this node, or nil.
|
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.
|
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.
|
8
|
+
|
9
|
+
# This method reflects that semantics and returns either:
|
10
|
+
# * nil if there are zero relationships of the given type and direction,
|
11
|
+
# * the relationship if there's exactly one, or
|
12
|
+
# * throws an unchecked exception in all other cases.
|
13
|
+
#
|
14
|
+
# This method should be used only in situations with an invariant as described above. In those situations, a "state-checking" method (e.g. #rel?) is not required,
|
15
|
+
# because this method behaves correctly "out of the box."
|
16
|
+
#
|
17
|
+
# @param (see #rel)
|
18
|
+
# @see Neo4j::Core::Node#wrapper #wrapper - The method used to wrap the node in a Ruby object if the node was found
|
19
|
+
def node(dir, type)
|
20
|
+
n = _node(dir, type)
|
21
|
+
n && n.wrapper
|
22
|
+
end
|
23
|
+
|
24
|
+
# Same as #node but instead returns an unwrapped native java node.
|
25
|
+
# @param (see #rel)
|
26
|
+
def _node(dir, type)
|
27
|
+
r = _rel(dir, type)
|
28
|
+
r && r._other_node(self._java_node)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Works like #rels method but instead returns the nodes.
|
32
|
+
# @param (see #rels)
|
33
|
+
# @see #rels
|
34
|
+
# @return [Enumerable<Neo4j::Node>]
|
35
|
+
def _nodes(dir, *types)
|
36
|
+
r = _rels(dir, *types)
|
37
|
+
case dir
|
38
|
+
when :outgoing then
|
39
|
+
Neo4j::Core::LazyMap.new(r, &:_end_node)
|
40
|
+
when :incoming then
|
41
|
+
Neo4j::Core::LazyMap.new(r, &:_start_node)
|
42
|
+
when :both then
|
43
|
+
Neo4j::Core::LazyMap.new(r) { |x| x._other_node(self) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Works like #rels method but instead returns the nodes.
|
48
|
+
# It does try to load a Ruby wrapper around each node
|
49
|
+
# @param (see #rels)
|
50
|
+
# @see Neo4j::Core::Node#wrapper #wrapper - The method used wrap to the node in a Ruby object if the node was found
|
51
|
+
# @return [Enumerable] an Enumeration of either Neo4j::Node objects or wrapped Neo4j::Node objects
|
52
|
+
# @notice it's possible that the same node is returned more then once because of several relationship reaching to the same node, see #outgoing for alternative
|
53
|
+
def nodes(dir, *types)
|
54
|
+
Neo4j::Core::LazyMap.new(_nodes(dir, *types), &:wrapper)
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# Returns an enumeration of relationship objects using the builder DSL pattern.
|
59
|
+
# It always returns relationships of depth one.
|
60
|
+
#
|
61
|
+
# @param [:both, :incoming, :outgoing] dir the direction of the relationship
|
62
|
+
# @param [String, Symbol] types the requested relationship types we want look for, if none it gets relationships of any type
|
63
|
+
# @return [Neo4j::Core::Rels::Traverser] an object which included the Ruby Enumerable mixin
|
64
|
+
#
|
65
|
+
# @example Return both incoming and outgoing relationships
|
66
|
+
# me.rels(:both, :friends, :work).each {|relationship|...}
|
67
|
+
#
|
68
|
+
# @example Only return outgoing relationship of given type
|
69
|
+
# me.rels(:outgoing, :friends).first.end_node # => my friend node
|
70
|
+
#
|
71
|
+
# @example All the relationships between me and another node of given dir & type
|
72
|
+
# me.rels(:outgoing, :friends).to_other(node)
|
73
|
+
#
|
74
|
+
# @example Delete all relationships between me and another node of given dir & type
|
75
|
+
# me.rels(:outgoing, :friends).to_other(node).del
|
76
|
+
#
|
77
|
+
# @see Neo4j::Core::Node#wrapper #wrapper - The method used wrap to the node in a Ruby object if the node was found
|
78
|
+
# @see Neo4j::Relationship#rel_type
|
79
|
+
# @raise an exception if the first parameter is not <tt>:both</tt>, <tt>;outgoing</tt> or <tt>:incoming</tt>
|
80
|
+
def rels(dir=:both, *types)
|
81
|
+
raise "Illegal argument, first argument must be :both, :incoming or :outgoing, got #{dir.inspect}" unless [:incoming, :outgoing, :both].include?(dir)
|
82
|
+
Neo4j::Core::Rels::Traverser.new(self, types, dir)
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# Returns the only relationship of a given type and direction that is attached to this node, or null.
|
87
|
+
# This is a convenience method that is used in the commonly occuring situation where a node has exactly zero or
|
88
|
+
# one relationships of a given type and direction to another node.
|
89
|
+
# Typically this invariant is maintained by the rest of the code: if at any time more than one such relationships
|
90
|
+
# exist, it is a fatal error that should generate an unchecked exception. This method reflects that semantics and
|
91
|
+
# returns either:
|
92
|
+
#
|
93
|
+
# * nil if there are zero relationships of the given type and direction,
|
94
|
+
# * the relationship if there's exactly one, or
|
95
|
+
# * raise an exception in all other cases.
|
96
|
+
# @param [:both, :incoming, :outgoing] dir the direction of the relationship
|
97
|
+
# @param [Symbol, String] type the type of relationship, see Neo4j::Core::Relationship#rel_type
|
98
|
+
# @return [Neo4j::Relationship, nil, Object] the Relationship or wrapper for the Relationship or nil
|
99
|
+
# @see Neo4j::Core::Relationship#rel_type
|
100
|
+
# @see Neo4j::Core::Node#wrapper #wrapper - The method used to wrap the node in a Ruby object if the node was found
|
101
|
+
def rel(dir, type)
|
102
|
+
result = _rel(dir, type)
|
103
|
+
result && result.wrapper
|
104
|
+
end
|
105
|
+
|
106
|
+
# Same as rel but does not return a ruby wrapped object but instead returns the Java object.
|
107
|
+
# @param (see #rel)
|
108
|
+
# @return [Neo4j::Relationship, nil]
|
109
|
+
# @see #rel
|
110
|
+
def _rel(dir, type)
|
111
|
+
get_single_relationship(ToJava.type_to_java(type), ToJava.dir_to_java(dir))
|
112
|
+
end
|
113
|
+
|
114
|
+
# Finds relationship starting from this node given a direction and/or relationship type(s).
|
115
|
+
# @param (see #rels)
|
116
|
+
# @return [Enumerable] of Neo4j::Relationship objects
|
117
|
+
def _rels(dir=:both, *types)
|
118
|
+
if types.size > 1
|
119
|
+
get_relationships(ToJava.dir_to_java(dir), ToJava.types_to_java(types))
|
120
|
+
elsif types.size == 1
|
121
|
+
get_relationships(ToJava.type_to_java(types[0]), ToJava.dir_to_java(dir))
|
122
|
+
else
|
123
|
+
get_relationships(ToJava.dir_to_java(dir))
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Check if the given relationship exists
|
128
|
+
# Returns true if there are one or more relationships from this node to other nodes
|
129
|
+
# with the given relationship.
|
130
|
+
#
|
131
|
+
# @param [:both, :incoming, :outgoing] dir optional default :both (either, :outgoing, :incoming, :both)
|
132
|
+
# @param [String,Symbol] type the key and value to be set, default any type
|
133
|
+
# @return [Boolean] true if one or more relationships exists for the given type and dir otherwise false
|
134
|
+
def rel?(dir=:both, type=nil)
|
135
|
+
if type
|
136
|
+
has_relationship(ToJava.type_to_java(type), ToJava.dir_to_java(dir))
|
137
|
+
else
|
138
|
+
has_relationship(ToJava.dir_to_java(dir))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
end
|