neo4j 1.0.0.beta.9 → 1.0.0.beta.10
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/README.rdoc +5 -1971
- data/lib/neo4j/mapping/class_methods/relationship.rb +2 -2
- data/lib/neo4j/mapping/decl_relationship_dsl.rb +6 -1
- data/lib/neo4j/mapping/has_n.rb +17 -1
- data/lib/neo4j/node_traverser.rb +14 -1
- data/lib/neo4j/rails/model.rb +127 -31
- data/lib/neo4j/rails/tx_methods.rb +11 -0
- data/lib/neo4j/rails/value.rb +44 -1
- data/lib/neo4j/version.rb +1 -1
- data/lib/neo4j.rb +1 -0
- metadata +4 -59
- data/lib/neo4j.old/batch_inserter.rb +0 -144
- data/lib/neo4j.old/config.rb +0 -138
- data/lib/neo4j.old/event_handler.rb +0 -73
- data/lib/neo4j.old/extensions/activemodel.rb +0 -158
- data/lib/neo4j.old/extensions/aggregate/aggregate_enum.rb +0 -40
- data/lib/neo4j.old/extensions/aggregate/ext/node_mixin.rb +0 -69
- data/lib/neo4j.old/extensions/aggregate/node_aggregate.rb +0 -8
- data/lib/neo4j.old/extensions/aggregate/node_aggregate_mixin.rb +0 -331
- data/lib/neo4j.old/extensions/aggregate/node_aggregator.rb +0 -216
- data/lib/neo4j.old/extensions/aggregate/node_group.rb +0 -43
- data/lib/neo4j.old/extensions/aggregate/prop_group.rb +0 -30
- data/lib/neo4j.old/extensions/aggregate/property_enum.rb +0 -24
- data/lib/neo4j.old/extensions/aggregate/props_aggregate.rb +0 -8
- data/lib/neo4j.old/extensions/aggregate/props_aggregate_mixin.rb +0 -31
- data/lib/neo4j.old/extensions/aggregate/props_aggregator.rb +0 -80
- data/lib/neo4j.old/extensions/aggregate.rb +0 -12
- data/lib/neo4j.old/extensions/find_path.rb +0 -117
- data/lib/neo4j.old/extensions/graph_algo/all_simple_paths.rb +0 -133
- data/lib/neo4j.old/extensions/graph_algo/neo4j-graph-algo-0.3.jar +0 -0
- data/lib/neo4j.old/extensions/graph_algo.rb +0 -1
- data/lib/neo4j.old/extensions/reindexer.rb +0 -104
- data/lib/neo4j.old/extensions/rest/rest.rb +0 -336
- data/lib/neo4j.old/extensions/rest/rest_mixin.rb +0 -193
- data/lib/neo4j.old/extensions/rest/server.rb +0 -50
- data/lib/neo4j.old/extensions/rest/stubs.rb +0 -141
- data/lib/neo4j.old/extensions/rest.rb +0 -21
- data/lib/neo4j.old/extensions/rest_master.rb +0 -34
- data/lib/neo4j.old/extensions/rest_slave.rb +0 -31
- data/lib/neo4j.old/extensions/tx_tracker.rb +0 -392
- data/lib/neo4j.old/indexer.rb +0 -187
- data/lib/neo4j.old/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
- data/lib/neo4j.old/jars/neo4j-kernel-1.0.jar +0 -0
- data/lib/neo4j.old/jars.rb +0 -6
- data/lib/neo4j.old/mixins/java_list_mixin.rb +0 -139
- data/lib/neo4j.old/mixins/java_node_mixin.rb +0 -205
- data/lib/neo4j.old/mixins/java_property_mixin.rb +0 -169
- data/lib/neo4j.old/mixins/java_relationship_mixin.rb +0 -60
- data/lib/neo4j.old/mixins/migration_mixin.rb +0 -157
- data/lib/neo4j.old/mixins/node_mixin.rb +0 -249
- data/lib/neo4j.old/mixins/property_class_methods.rb +0 -265
- data/lib/neo4j.old/mixins/rel_class_methods.rb +0 -167
- data/lib/neo4j.old/mixins/relationship_mixin.rb +0 -103
- data/lib/neo4j.old/neo.rb +0 -247
- data/lib/neo4j.old/node.rb +0 -49
- data/lib/neo4j.old/reference_node.rb +0 -15
- data/lib/neo4j.old/relationship.rb +0 -85
- data/lib/neo4j.old/relationships/decl_relationship_dsl.rb +0 -164
- data/lib/neo4j.old/relationships/has_list.rb +0 -101
- data/lib/neo4j.old/relationships/has_n.rb +0 -129
- data/lib/neo4j.old/relationships/node_traverser.rb +0 -138
- data/lib/neo4j.old/relationships/relationship_dsl.rb +0 -149
- data/lib/neo4j.old/relationships/traversal_position.rb +0 -50
- data/lib/neo4j.old/relationships/wrappers.rb +0 -51
- data/lib/neo4j.old/search_result.rb +0 -72
- data/lib/neo4j.old/transaction.rb +0 -254
- data/lib/neo4j.old/version.rb +0 -3
data/lib/neo4j.old/indexer.rb
DELETED
@@ -1,187 +0,0 @@
|
|
1
|
-
module Neo4j
|
2
|
-
|
3
|
-
# This class is responsible for both knowing which nodes that needs to be reindexed
|
4
|
-
# and how to perform the reindex operation (the document_updaters attribute).
|
5
|
-
#
|
6
|
-
# There is one Indexer per Node root class.
|
7
|
-
#
|
8
|
-
class Indexer #:nodoc:
|
9
|
-
attr_reader :document_updaters, :index_id
|
10
|
-
attr_reader :property_indexer # for testing purpose
|
11
|
-
|
12
|
-
def initialize(indexed_class, query_for_nodes)
|
13
|
-
@relationship_indexers = {}
|
14
|
-
@query_for_nodes = query_for_nodes
|
15
|
-
@property_indexer = PropertyIndexer.new
|
16
|
-
@document_updaters = [@property_indexer]
|
17
|
-
# the file name of the lucene index if kept on disk
|
18
|
-
@index_id = "/" + indexed_class.to_s.gsub('::', '/')
|
19
|
-
end
|
20
|
-
|
21
|
-
# Returns the Indexer for the given Neo4j::NodeMixin class
|
22
|
-
def self.instance(clazz, query_for_nodes = true)
|
23
|
-
@instances ||= {}
|
24
|
-
@instances[clazz.root_class] ||= Indexer.new(clazz.root_class, query_for_nodes)
|
25
|
-
@instances[clazz.root_class]
|
26
|
-
end
|
27
|
-
|
28
|
-
# only for testing purpose, e.g we need to redefine an existing class
|
29
|
-
def self.remove_instance(clazz)
|
30
|
-
@instances.delete(clazz.root_class) if !@instances.nil? && clazz.respond_to?(:root_class)
|
31
|
-
end
|
32
|
-
|
33
|
-
|
34
|
-
# (Re)index the given node
|
35
|
-
def self.index(node)
|
36
|
-
indexer = instance(node.class)
|
37
|
-
indexer.index(node)
|
38
|
-
end
|
39
|
-
|
40
|
-
def find(query,block)
|
41
|
-
SearchResult.new lucene_index, query, @query_for_nodes, &block
|
42
|
-
end
|
43
|
-
|
44
|
-
def add_index_on_property(prop)
|
45
|
-
@property_indexer.properties << prop.to_sym
|
46
|
-
end
|
47
|
-
|
48
|
-
def remove_index_on_property(prop)
|
49
|
-
@property_indexer.properties.delete prop.to_sym
|
50
|
-
end
|
51
|
-
|
52
|
-
def add_index_in_relationship_on_property(updater_clazz, rel_name, rel_type, prop, namespace_type)
|
53
|
-
unless relationship_indexer_for?(namespace_type)
|
54
|
-
indexer = new_relationship_indexer_for(namespace_type, rel_name.to_sym)
|
55
|
-
self.class.instance(updater_clazz).document_updaters << indexer
|
56
|
-
end
|
57
|
-
|
58
|
-
# TODO make sure the same index is not added twice
|
59
|
-
relationship_indexer_for(namespace_type).properties << prop.to_sym
|
60
|
-
end
|
61
|
-
|
62
|
-
def index(node)
|
63
|
-
document = {:id => node.neo_id }
|
64
|
-
|
65
|
-
@document_updaters.each do |updater|
|
66
|
-
updater.update_document(document, node)
|
67
|
-
end
|
68
|
-
|
69
|
-
lucene_index << document
|
70
|
-
end
|
71
|
-
|
72
|
-
def delete_index(node)
|
73
|
-
lucene_index.delete(node.neo_id)
|
74
|
-
end
|
75
|
-
|
76
|
-
|
77
|
-
def lucene_index
|
78
|
-
Lucene::Index.new(@index_id)
|
79
|
-
end
|
80
|
-
|
81
|
-
def field_infos
|
82
|
-
lucene_index.field_infos
|
83
|
-
end
|
84
|
-
|
85
|
-
def on_property_changed(node, prop)
|
86
|
-
@relationship_indexers.values.each {|indexer| indexer.on_property_changed(node, prop.to_sym)}
|
87
|
-
@property_indexer.on_property_changed(node,prop.to_sym)
|
88
|
-
end
|
89
|
-
|
90
|
-
def on_relationship_created(node, rel_type)
|
91
|
-
@relationship_indexers.values.each {|indexer| indexer.on_relationship_created(node, rel_type.to_sym)}
|
92
|
-
end
|
93
|
-
|
94
|
-
def on_relationship_deleted(node, rel_type)
|
95
|
-
@relationship_indexers.values.each {|indexer| indexer.on_relationship_deleted(node, rel_type.to_sym)}
|
96
|
-
end
|
97
|
-
|
98
|
-
def relationship_indexer_for(rel_type)
|
99
|
-
@relationship_indexers[rel_type.to_sym]
|
100
|
-
end
|
101
|
-
|
102
|
-
def relationship_indexer_for?(rel_type)
|
103
|
-
!relationship_indexer_for(rel_type.to_sym).nil?
|
104
|
-
end
|
105
|
-
|
106
|
-
def new_relationship_indexer_for(rel_type, rel_name)
|
107
|
-
@relationship_indexers[rel_type.to_sym] = RelationshipIndexer.new(rel_name.to_sym, rel_type.to_sym)
|
108
|
-
end
|
109
|
-
|
110
|
-
end
|
111
|
-
|
112
|
-
|
113
|
-
class PropertyIndexer #:nodoc:
|
114
|
-
attr_reader :properties
|
115
|
-
|
116
|
-
def initialize
|
117
|
-
@properties = []
|
118
|
-
end
|
119
|
-
|
120
|
-
def on_property_changed(node, prop)
|
121
|
-
Indexer.index(node) if @properties.include?(prop)
|
122
|
-
end
|
123
|
-
|
124
|
-
def update_document(document, node)
|
125
|
-
# we have to check that the property exists since the index can be defined in a subclass
|
126
|
-
@properties.each {|prop| document[prop.to_sym] = node.send(prop) if node.respond_to?(prop)}
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
|
131
|
-
# If node class A has a relationship with type 'd' to node class B
|
132
|
-
# A.x -d-> B.y A.index d.y
|
133
|
-
# If property y on a B node changes then all its nodes in the relationship 'd' will
|
134
|
-
# be reindexed. Those nodes (which will be of type node class A) will use the same RelationshipIndexer to update the
|
135
|
-
# index document with key field 'd.y' and values of property y of all nodes in the
|
136
|
-
# relationship 'd'
|
137
|
-
#
|
138
|
-
class RelationshipIndexer #:nodoc:
|
139
|
-
attr_reader :rel_type, :properties
|
140
|
-
|
141
|
-
def initialize(rel_name, rel_type)
|
142
|
-
@properties = []
|
143
|
-
@rel_type = rel_type
|
144
|
-
@rel_name = rel_name
|
145
|
-
end
|
146
|
-
|
147
|
-
def on_property_changed(node, prop)
|
148
|
-
# make sure we're interested in indexing this property
|
149
|
-
reindex_related_nodes(node) if @properties.include?(prop)
|
150
|
-
end
|
151
|
-
|
152
|
-
def on_relationship_deleted(node, rel_type)
|
153
|
-
Indexer.index(node) if @rel_type == rel_type
|
154
|
-
end
|
155
|
-
|
156
|
-
def on_relationship_created(node, rel_type)
|
157
|
-
# make sure we're interested in indexing this relationship
|
158
|
-
if @rel_type == rel_type
|
159
|
-
reindex_related_nodes(node)
|
160
|
-
Indexer.index(node)
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
def reindex_related_nodes(node)
|
165
|
-
related_nodes = node.rels.both(@rel_type).nodes
|
166
|
-
related_nodes.each do |related_node|
|
167
|
-
Indexer.index(related_node)
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
def index_key(property)
|
172
|
-
"#@rel_name.#{property}".to_sym
|
173
|
-
end
|
174
|
-
|
175
|
-
def update_document(document, node)
|
176
|
-
relationships = node.rels.both(@rel_type).nodes
|
177
|
-
relationships.each do |other_node|
|
178
|
-
@properties.each do |p|
|
179
|
-
index_key = index_key(p)
|
180
|
-
document[index_key] ||= []
|
181
|
-
document[index_key] << other_node.send(p)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
end
|
Binary file
|
Binary file
|
data/lib/neo4j.old/jars.rb
DELETED
@@ -1,139 +0,0 @@
|
|
1
|
-
module Neo4j::JavaListMixin
|
2
|
-
|
3
|
-
# --------------------------------------------------------------------------
|
4
|
-
# List methods
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
# Returns true if this nodes belongs to a list of the given name
|
9
|
-
#
|
10
|
-
def list?(list_name)
|
11
|
-
regexp = Regexp.new "_list_#{list_name}"
|
12
|
-
rels.both.find { |rel| regexp.match(rel.relationship_type.to_s) } != nil
|
13
|
-
end
|
14
|
-
|
15
|
-
# Returns one or more list of the given list_name and list_node.
|
16
|
-
# If the optional list_node parameter is given the specific list belonging to that list node will be returned (or nil)
|
17
|
-
# If only the list_name parameter is given the first list matching the given list_name will be returned.
|
18
|
-
# (There might be several list of the same name but from different list nodes.)
|
19
|
-
#
|
20
|
-
# ==== Returns
|
21
|
-
#
|
22
|
-
# The node but with the extra instance methods
|
23
|
-
# * next - the next node in the list
|
24
|
-
# * prev - the previous node in the list
|
25
|
-
# * head - the head node (the node that has the has_list method)
|
26
|
-
# * size (if the size optional parameter is given in the has_list class method)
|
27
|
-
#
|
28
|
-
# ==== Example
|
29
|
-
# class Foo
|
30
|
-
# include Neo4j::NodeMixin
|
31
|
-
# has_list :baar
|
32
|
-
# end
|
33
|
-
#
|
34
|
-
# f = Foo.new
|
35
|
-
# n1 = Neo4j::Node.new
|
36
|
-
# n2 = Neo4j::Node.new
|
37
|
-
# f.baar << n1 << n2
|
38
|
-
#
|
39
|
-
# n2.list(:baar).next # => n1
|
40
|
-
# n2.list(:baar).prev # => f
|
41
|
-
# n2.list(:baar).head # => f
|
42
|
-
#
|
43
|
-
def list(list_name, list_node = nil)
|
44
|
-
if list_node
|
45
|
-
list_id = "_list_#{list_name}_#{list_node.neo_id}"
|
46
|
-
add_list_item_methods(list_id, list_name, list_node)
|
47
|
-
else
|
48
|
-
list_items = []
|
49
|
-
lists(list_name) {|list_item| list_items << list_item}
|
50
|
-
list_items[0]
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
|
55
|
-
# Returns an array of lists with the given names that this nodes belongs to.
|
56
|
-
# Expects a block to yield for each found list
|
57
|
-
# That block will be given one parameter - the node with the extra method (see #list method)
|
58
|
-
#
|
59
|
-
def lists(*list_names)
|
60
|
-
list_names.collect! {|n| n.to_sym}
|
61
|
-
|
62
|
-
rels.both.inject({}) do |res, rel|
|
63
|
-
rel_type = rel.relationship_type.to_s
|
64
|
-
md = /_list_(\w*)_(\d*)/.match(rel_type)
|
65
|
-
next res if md.nil?
|
66
|
-
next res unless list_names.empty? || list_names.include?(md[1].to_sym)
|
67
|
-
res[rel_type] = [md[1], Neo4j.load_node(md[2])]
|
68
|
-
res
|
69
|
-
end.each_pair do |rel_id, list_name_and_head_node|
|
70
|
-
yield self.add_list_item_methods(rel_id, list_name_and_head_node[0], list_name_and_head_node[1]) # clone ?
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
|
75
|
-
def add_list_item_methods(list_id, list_name, head_node) #:no_doc:
|
76
|
-
mod = Module.new do
|
77
|
-
define_method :head do
|
78
|
-
head_node
|
79
|
-
end
|
80
|
-
|
81
|
-
define_method :size do
|
82
|
-
head_node["_#{list_name}_size"] || 0
|
83
|
-
end
|
84
|
-
|
85
|
-
define_method :size= do |new_size|
|
86
|
-
head_node["_#{list_name}_size"] = new_size
|
87
|
-
end
|
88
|
-
|
89
|
-
define_method :next do
|
90
|
-
next_node = rels.outgoing(list_id).nodes.first
|
91
|
-
return nil if next_node.nil?
|
92
|
-
next_node.add_list_item_methods(list_id, list_name, head_node)
|
93
|
-
next_node
|
94
|
-
end
|
95
|
-
|
96
|
-
define_method :next= do |new_next|
|
97
|
-
# does it have a next pointer ?
|
98
|
-
next_rel = rels.outgoing(list_id).first
|
99
|
-
# delete the relationship if exists
|
100
|
-
next_rel.delete if (next_rel.nil?)
|
101
|
-
rels.outgoing(list_id) << new_next unless new_next.nil?
|
102
|
-
nil
|
103
|
-
end
|
104
|
-
|
105
|
-
define_method :prev do
|
106
|
-
prev_node = rels.incoming(list_id).nodes.first
|
107
|
-
return nil if prev_node.nil?
|
108
|
-
prev_node.add_list_item_methods(list_id, list_name, head_node)
|
109
|
-
prev_node
|
110
|
-
end
|
111
|
-
|
112
|
-
define_method :prev= do |new_prev|
|
113
|
-
# does it have a next pointer ?
|
114
|
-
prev_rel = rels.incoming(list_id).first
|
115
|
-
# delete the relationship if exists
|
116
|
-
prev_rel.delete if (prev_rel.nil?)
|
117
|
-
rels.outgoing(list_id) << new_prev unless new_prev.nil?
|
118
|
-
nil
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
self.extend mod
|
123
|
-
end
|
124
|
-
|
125
|
-
def add_list_head_methods(list_name) # :nodoc:
|
126
|
-
prop_name = "_#{list_name}_size".to_sym
|
127
|
-
mod = Module.new do
|
128
|
-
define_method :size do
|
129
|
-
self[prop_name] || 0
|
130
|
-
end
|
131
|
-
|
132
|
-
define_method :size= do |new_size|
|
133
|
-
self[prop_name]=new_size
|
134
|
-
end
|
135
|
-
end
|
136
|
-
self.extend mod
|
137
|
-
end
|
138
|
-
|
139
|
-
end
|
@@ -1,205 +0,0 @@
|
|
1
|
-
module Neo4j::JavaNodeMixin
|
2
|
-
|
3
|
-
|
4
|
-
# Check if the given relationship exists
|
5
|
-
# Returns true if there are one or more relationships from this node to other nodes
|
6
|
-
# with the given relationship.
|
7
|
-
# It will not return true only because the relationship is defined.
|
8
|
-
#
|
9
|
-
# ==== Parameters
|
10
|
-
# rel_name<#to_s>:: the key and value to be set
|
11
|
-
# dir:: optional default :outgoing (either, :outgoing, :incoming, :both)
|
12
|
-
#
|
13
|
-
# ==== Returns
|
14
|
-
# true if one or more relationships exists for the given rel_name and dir
|
15
|
-
# otherwise false
|
16
|
-
#
|
17
|
-
def rel? (rel_name, dir=:outgoing)
|
18
|
-
type = org.neo4j.graphdb.DynamicRelationshipType.withName(rel_name.to_s)
|
19
|
-
java_dir = _to_java_direction(dir)
|
20
|
-
hasRelationship(type, java_dir)
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
# Returns a Neo4j::Relationships::RelationshipDSL object for accessing relationships from and to this node.
|
25
|
-
# The Neo4j::Relationships::RelationshipDSL is an Enumerable that returns Neo4j::RelationshipMixin objects.
|
26
|
-
#
|
27
|
-
# ==== Returns
|
28
|
-
# A Neo4j::Relationships::RelationshipDSL object
|
29
|
-
#
|
30
|
-
# ==== See Also
|
31
|
-
# * Neo4j::Relationships::RelationshipDSL
|
32
|
-
# * Neo4j::RelationshipMixin
|
33
|
-
#
|
34
|
-
# ==== Example
|
35
|
-
#
|
36
|
-
# person_node.rels.outgoing(:friends).each { ... }
|
37
|
-
#
|
38
|
-
def rels(direction = :outgoing)
|
39
|
-
Neo4j::Relationships::RelationshipDSL.new(self, direction)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Returns a single relationship or nil if none available.
|
43
|
-
# If there are more then one relationship of the given type it will raise an exception.
|
44
|
-
#
|
45
|
-
# ==== Parameters
|
46
|
-
# type<#to_s>:: the key and value to be set
|
47
|
-
# dir:: optional, default :outgoing (either, :outgoing, :incoming, :both)
|
48
|
-
# raw:: optional, true|false (false default). If false return the ruby wrapped relationship object instead of the raw java neo4j obejct.
|
49
|
-
|
50
|
-
#
|
51
|
-
# ==== Returns
|
52
|
-
# An object that mixins the Neo4j::RelationshipMixin representing the given relationship type or nil if there are no relationships.
|
53
|
-
# If there are more then one relationship it will raise an Exception (java exception of type org.neo4j.graphdb.NotFoundException)
|
54
|
-
#
|
55
|
-
# ==== See Also
|
56
|
-
# * JavaDoc for http://api.neo4j.org/current/org/neo4j/api/core/Node.html#getSingleRelationship(org.neo4j.graphdb.RelationshipType,%20org.neo4j.graphdb.Direction)
|
57
|
-
# * Neo4j::RelationshipMixin
|
58
|
-
#
|
59
|
-
# ==== Example
|
60
|
-
#
|
61
|
-
# person_node.rel(:address).end_node[:street]
|
62
|
-
#
|
63
|
-
def rel(rel_name, dir=:outgoing, raw=false)
|
64
|
-
java_dir = _to_java_direction(dir)
|
65
|
-
rel_type = org.neo4j.graphdb.DynamicRelationshipType.withName(rel_name.to_s)
|
66
|
-
rel = getSingleRelationship(rel_type, java_dir)
|
67
|
-
return nil if rel.nil?
|
68
|
-
return rel.wrapper unless raw
|
69
|
-
rel
|
70
|
-
end
|
71
|
-
|
72
|
-
|
73
|
-
# Adds an outgoing relationship from this node to another node.
|
74
|
-
# Will trigger a relationship_created event.
|
75
|
-
#
|
76
|
-
# ==== Parameters
|
77
|
-
# type:: the relationship type between the nodes (respond_to :to_s)
|
78
|
-
# to:: the other node (Neo4j::Node || kind_of?(Neo4j::NodeMixin)
|
79
|
-
#
|
80
|
-
# ==== Returns
|
81
|
-
# a Neo4j::Relationship object
|
82
|
-
#
|
83
|
-
# === Example
|
84
|
-
# nodeA = Neo4j::Node.new
|
85
|
-
# nodeB = Neo4j::Node.new
|
86
|
-
# nodeA.add_rel(:friend, nodeB)
|
87
|
-
#
|
88
|
-
|
89
|
-
# all creation of relationships uses this method
|
90
|
-
def add_rel (type, to, rel_clazz = nil) # :nodoc:
|
91
|
-
java_type = org.neo4j.graphdb.DynamicRelationshipType.withName(type.to_s)
|
92
|
-
java_rel = createRelationshipTo(to._java_node, java_type)
|
93
|
-
# check if we should create a wrapped Ruby Relationship class or use the raw java one.
|
94
|
-
rel = (rel_clazz.nil?) ? java_rel : rel_clazz.new(java_rel)
|
95
|
-
Neo4j.event_handler.relationship_created(rel)
|
96
|
-
@_wrapper.class.indexer.on_relationship_created(@_wrapper, type) if @_wrapper
|
97
|
-
rel
|
98
|
-
end
|
99
|
-
|
100
|
-
def _to_java_direction(dir) # :nodoc:
|
101
|
-
case dir
|
102
|
-
when :outgoing
|
103
|
-
org.neo4j.graphdb.Direction::OUTGOING
|
104
|
-
when :incoming
|
105
|
-
org.neo4j.graphdb.Direction::INCOMING
|
106
|
-
when :both
|
107
|
-
org.neo4j.graphdb.Direction::BOTH
|
108
|
-
else
|
109
|
-
raise "Unknown parameter: '#{dir}', only accept :outgoing, :incoming or :both"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
|
114
|
-
# Returns a Neo4j::Relationships::NodeTraverser object for traversing outgoing nodes from and to this node.
|
115
|
-
# The Neo4j::Relationships::NodeTraverser is an Enumerable that returns Neo4j::NodeMixin objects.
|
116
|
-
#
|
117
|
-
# ==== See Also
|
118
|
-
# Neo4j::Relationships::NodeTraverser
|
119
|
-
#
|
120
|
-
# ==== Example
|
121
|
-
#
|
122
|
-
# person_node.outgoing(:friends).each { ... }
|
123
|
-
# person_node.outgoing(:friends).raw(true).each { }
|
124
|
-
#
|
125
|
-
# The raw false parameter means that the ruby wrapper object will not be loaded, instead the raw Java Neo4j object will be used,
|
126
|
-
# it might improve the performance.
|
127
|
-
#
|
128
|
-
def outgoing(*args)
|
129
|
-
Neo4j::Relationships::NodeTraverser.new(self).outgoing(*args)
|
130
|
-
end
|
131
|
-
|
132
|
-
# Returns a Neo4j::Relationships::NodeTraverser object for traversing outgoing nodes from and to this node.
|
133
|
-
# The Neo4j::Relationships::NodeTraverser is an Enumerable that returns Neo4j::NodeMixin objects.
|
134
|
-
#
|
135
|
-
# ==== See Also
|
136
|
-
# Neo4j::Relationships::NodeTraverser
|
137
|
-
#
|
138
|
-
# ==== Example
|
139
|
-
#
|
140
|
-
# person_node.incoming(:friends).each { ... }
|
141
|
-
# person_node.incoming(:friends).raw(true).each { }
|
142
|
-
#
|
143
|
-
# The raw false parameter means that the ruby wrapper object will not be loaded, instead the raw Java Neo4j object will be used,
|
144
|
-
# it might improve the performance.
|
145
|
-
#
|
146
|
-
def incoming(*args)
|
147
|
-
Neo4j::Relationships::NodeTraverser.new(self).incoming(*args)
|
148
|
-
end
|
149
|
-
|
150
|
-
|
151
|
-
# Deletes this node.
|
152
|
-
# Deletes all relationships as well.
|
153
|
-
# Invoking any methods on this node after delete() has returned is invalid and may lead to unspecified behavior.
|
154
|
-
#
|
155
|
-
# :api: public
|
156
|
-
def del
|
157
|
-
Neo4j.event_handler.node_deleted(wrapper)
|
158
|
-
|
159
|
-
# delete outgoing relationships, and check for cascade delete
|
160
|
-
rels.outgoing.each { |r| r.del; r.end_node.del if r[:_cascade_delete_outgoing]}
|
161
|
-
|
162
|
-
rels.incoming.each do |r|
|
163
|
-
r.del
|
164
|
-
if r[:_cascade_delete_incoming]
|
165
|
-
node_id = r[:_cascade_delete_incoming]
|
166
|
-
node = Neo4j.load_node(node_id)
|
167
|
-
# check node has no outgoing relationships
|
168
|
-
no_outgoing = node.rels.outgoing.empty?
|
169
|
-
# check node has only incoming relationship with cascade_delete_incoming
|
170
|
-
no_incoming = node.rels.incoming.find{|r| !node.ignore_incoming_cascade_delete?(r)}.nil?
|
171
|
-
# only cascade delete incoming if no outgoing and no incoming (exception cascade_delete_incoming) relationships
|
172
|
-
node.del if no_outgoing and no_incoming
|
173
|
-
end
|
174
|
-
end
|
175
|
-
delete
|
176
|
-
@_wrapper.class.indexer.delete_index(self) if @_wrapper
|
177
|
-
end
|
178
|
-
|
179
|
-
# --------------------------------------------------------------------------
|
180
|
-
# Debug
|
181
|
-
#
|
182
|
-
|
183
|
-
# Used for debugging purpose, traverse the graph of given depth and direction and prints nodes and relationship information.
|
184
|
-
def print(levels = 0, dir = :outgoing)
|
185
|
-
print_sub(0, levels, dir)
|
186
|
-
end
|
187
|
-
|
188
|
-
def print_sub(level, max_level, dir) # :nodoc:
|
189
|
-
spaces = " " * level
|
190
|
-
node_class = (self[:_classname].nil?) ? Neo4j::Node.to_s : self[:_classname]
|
191
|
-
node_desc = "#{spaces}neo_id=#{neo_id} #{node_class}"
|
192
|
-
props.each_pair {|key, value| next if %w[id].include?(key) or key.match(/^_/) ; node_desc << " #{key}='#{value}'"}
|
193
|
-
puts node_desc
|
194
|
-
|
195
|
-
if (level != max_level)
|
196
|
-
rels(dir).each do |rel|
|
197
|
-
cascade_desc = ""
|
198
|
-
cascade_desc << "cascade in: #{rel[:_cascade_delete_incoming]}" if rel.property?(:_cascade_delete_incoming)
|
199
|
-
cascade_desc << "cascade out: #{rel[:_cascade_delete_outgoing]}" if rel.property?(:_cascade_delete_outgoing)
|
200
|
-
rel.other_node(self).print_sub(level + 1, max_level, dir)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
end
|
@@ -1,169 +0,0 @@
|
|
1
|
-
module Neo4j::JavaPropertyMixin
|
2
|
-
|
3
|
-
# This is the property to use to map ruby classes to Neo4j Nodes
|
4
|
-
CLASSNAME_PROPERTY = "_classname"
|
5
|
-
|
6
|
-
# Returns the unique id of this node.
|
7
|
-
# Ids are garbage collected over time so are only guaranteed to be unique at a specific set of time: if the node is deleted,
|
8
|
-
# it's likely that a new node at some point will get the old id. Note: this make node ids brittle as public APIs.
|
9
|
-
def neo_id
|
10
|
-
getId
|
11
|
-
end
|
12
|
-
|
13
|
-
def _wrapper=(wrapper) # :nodoc:
|
14
|
-
@_wrapper = wrapper
|
15
|
-
end
|
16
|
-
|
17
|
-
def _java_node
|
18
|
-
self
|
19
|
-
end
|
20
|
-
|
21
|
-
# Returns true if this property container has a property accessible through the given key, false otherwise.
|
22
|
-
def property?(key)
|
23
|
-
has_property?(key.to_s)
|
24
|
-
end
|
25
|
-
|
26
|
-
# Returns the given property if it exist or nil if it does not exist.
|
27
|
-
def [](key)
|
28
|
-
return unless property?(key)
|
29
|
-
if @_wrapper and @_wrapper.class.marshal?(key)
|
30
|
-
Marshal.load(String.from_java_bytes(get_property(key.to_s)))
|
31
|
-
else
|
32
|
-
get_property(key.to_s)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Sets the given property to given value.
|
37
|
-
# Will generate an event if the property does not start with '_' (which could be an internal property, like _classname)
|
38
|
-
#
|
39
|
-
def []=(key, value)
|
40
|
-
k = key.to_s
|
41
|
-
old_value = self[key]
|
42
|
-
|
43
|
-
if value.nil?
|
44
|
-
delete_property(k)
|
45
|
-
elsif @_wrapper and @_wrapper.class.marshal?(key)
|
46
|
-
setProperty(k, Marshal.dump(value).to_java_bytes)
|
47
|
-
else
|
48
|
-
value = java.lang.Double.new(value) if value.is_a? Float
|
49
|
-
setProperty(k, value)
|
50
|
-
end
|
51
|
-
|
52
|
-
if (@_wrapper and k[0, 1] != '_') # do not want events on internal properties
|
53
|
-
@_wrapper.class.indexer.on_property_changed(@_wrapper, k) if @_wrapper.class.respond_to? :indexer
|
54
|
-
Neo4j.event_handler.property_changed(@_wrapper, k, old_value, value)
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
|
-
# Removes the property from this node.
|
61
|
-
# This is same as setting a property value to nil.
|
62
|
-
#
|
63
|
-
# For more information see JavaDoc PropertyContainer#removeProperty
|
64
|
-
#
|
65
|
-
# ==== Example
|
66
|
-
# a = Node.new
|
67
|
-
# a[:foo] = 2
|
68
|
-
# a.delete_property('foo')
|
69
|
-
# a[:foo] # => nil
|
70
|
-
#
|
71
|
-
# ==== Returns
|
72
|
-
# <tt>true</tt> if the property was removed, <tt>false</tt> otherwise
|
73
|
-
#
|
74
|
-
def delete_property (name)
|
75
|
-
removed = !removeProperty(name).nil?
|
76
|
-
if (removed and @_wrapper and name[0] != '_') # do not want events on internal properties
|
77
|
-
@_wrapper.class.indexer.on_property_changed(self, name)
|
78
|
-
end
|
79
|
-
removed
|
80
|
-
end
|
81
|
-
|
82
|
-
# Returns a hash of all properties.
|
83
|
-
#
|
84
|
-
# === Returns
|
85
|
-
# Hash:: property key and property value with the '_neo_id' as the neo_id
|
86
|
-
#
|
87
|
-
def props
|
88
|
-
ret = {"_neo_id" => getId()}
|
89
|
-
iter = getPropertyKeys.iterator
|
90
|
-
while (iter.hasNext) do
|
91
|
-
key = iter.next
|
92
|
-
ret[key] = getProperty(key)
|
93
|
-
end
|
94
|
-
ret
|
95
|
-
end
|
96
|
-
|
97
|
-
# Updates this node/relationship's properties by using the provided struct/hash.
|
98
|
-
# If the option <code>{:strict => true}</code> is given, any properties present on
|
99
|
-
# the node but not present in the hash will be removed from the node.
|
100
|
-
#
|
101
|
-
# === Parameters
|
102
|
-
# struct_or_hash<#each_pair>:: the key and value to be set, should respond to 'each_pair'
|
103
|
-
# options:: further options defining the context of the update, should be a Hash
|
104
|
-
#
|
105
|
-
# === Returns
|
106
|
-
# self
|
107
|
-
#
|
108
|
-
def update(struct_or_hash, options={})
|
109
|
-
strict = options[:strict]
|
110
|
-
keys_to_delete = props.keys - %w(_neo_id _classname) if strict
|
111
|
-
struct_or_hash.each_pair do |key, value|
|
112
|
-
next if %w(_neo_id _classname).include? key.to_s # do not allow special properties to be mass assigned
|
113
|
-
keys_to_delete.delete(key) if strict
|
114
|
-
setter_meth = "#{key}=".to_sym
|
115
|
-
if @_wrapper && @_wrapper.respond_to?(setter_meth)
|
116
|
-
@_wrapper.send(setter_meth, value)
|
117
|
-
else
|
118
|
-
self[key] = value
|
119
|
-
end
|
120
|
-
end
|
121
|
-
keys_to_delete.each{|key| delete_property(key) } if strict
|
122
|
-
self
|
123
|
-
end
|
124
|
-
|
125
|
-
|
126
|
-
def equal?(o)
|
127
|
-
eql?(o)
|
128
|
-
end
|
129
|
-
|
130
|
-
def eql?(o)
|
131
|
-
return false unless o.respond_to?(:neo_id)
|
132
|
-
o.neo_id == neo_id
|
133
|
-
end
|
134
|
-
|
135
|
-
def ==(o)
|
136
|
-
eql?(o)
|
137
|
-
end
|
138
|
-
|
139
|
-
|
140
|
-
# Same as neo_id but returns a String instead of a Fixnum.
|
141
|
-
# Used by Ruby on Rails.
|
142
|
-
#
|
143
|
-
def to_param
|
144
|
-
neo_id.to_s
|
145
|
-
end
|
146
|
-
|
147
|
-
# Loads a Neo node wrapper if possible
|
148
|
-
# If the neo property '_classname' does not exist then it will map the neo node to the ruby class Neo4j::Node
|
149
|
-
def wrapper
|
150
|
-
return self unless wrapper?
|
151
|
-
@_wrapper ||= wrapper_class.new(self)
|
152
|
-
@_wrapper
|
153
|
-
end
|
154
|
-
|
155
|
-
def wrapper?
|
156
|
-
property?(CLASSNAME_PROPERTY)
|
157
|
-
end
|
158
|
-
|
159
|
-
def wrapper_class # :nodoc:
|
160
|
-
return nil unless wrapper?
|
161
|
-
classname = get_property(CLASSNAME_PROPERTY)
|
162
|
-
classname.split("::").inject(Kernel) do |container, name|
|
163
|
-
container.const_get(name.to_s)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
|
168
|
-
end
|
169
|
-
|