neo4j 1.2.6-java → 1.3.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. data/CHANGELOG +16 -0
  2. data/README.rdoc +11 -0
  3. data/bin/neo4j-upgrade +72 -0
  4. data/lib/neo4j.rb +18 -19
  5. data/lib/neo4j/algo/algo.rb +2 -1
  6. data/lib/neo4j/database.rb +12 -0
  7. data/lib/neo4j/event_handler.rb +69 -7
  8. data/lib/neo4j/has_list/class_methods.rb +1 -1
  9. data/lib/neo4j/has_list/mapping.rb +13 -16
  10. data/lib/neo4j/index/class_methods.rb +9 -3
  11. data/lib/neo4j/index/index.rb +2 -1
  12. data/lib/neo4j/index/indexer.rb +3 -2
  13. data/lib/neo4j/index/indexer_registry.rb +1 -1
  14. data/lib/neo4j/jars/core/neo4j-community-1.5.jar +0 -0
  15. data/lib/neo4j/jars/core/neo4j-cypher-1.5.jar +0 -0
  16. data/lib/neo4j/jars/core/{neo4j-graph-algo-1.4.1.jar → neo4j-graph-algo-1.5.jar} +0 -0
  17. data/lib/neo4j/jars/core/neo4j-graph-matching-1.5.jar +0 -0
  18. data/lib/neo4j/jars/core/neo4j-jmx-1.5.jar +0 -0
  19. data/lib/neo4j/jars/core/neo4j-kernel-1.5.jar +0 -0
  20. data/lib/neo4j/jars/core/{neo4j-lucene-index-1.4.1.jar → neo4j-lucene-index-1.5.jar} +0 -0
  21. data/lib/neo4j/jars/{ha/neo4j-shell-1.4.1.jar → core/neo4j-shell-1.5.jar} +0 -0
  22. data/lib/neo4j/jars/core/neo4j-udc-1.5.jar +0 -0
  23. data/lib/neo4j/jars/{ha → core}/org.apache.servicemix.bundles.jline-0.9.94_1.jar +0 -0
  24. data/lib/neo4j/jars/core/scala-library-2.9.0-1.jar +0 -0
  25. data/lib/neo4j/jars/core/server-api-1.5.jar +0 -0
  26. data/lib/neo4j/jars/ha/neo4j-backup-1.5.jar +0 -0
  27. data/lib/neo4j/jars/ha/neo4j-com-1.5.jar +0 -0
  28. data/lib/neo4j/jars/ha/neo4j-enterprise-1.5.jar +0 -0
  29. data/lib/neo4j/jars/ha/neo4j-ha-1.5.jar +0 -0
  30. data/lib/neo4j/jars/ha/neo4j-management-1.5.jar +0 -0
  31. data/lib/neo4j/jars/ha/org.apache.servicemix.bundles.netty-3.2.5.Final_1.jar +0 -0
  32. data/lib/neo4j/jars/ha/slf4j-api-1.6.1.jar +0 -0
  33. data/lib/neo4j/neo4j.rb +16 -0
  34. data/lib/neo4j/node_mixin/node_mixin.rb +2 -2
  35. data/lib/neo4j/rails/attributes.rb +9 -5
  36. data/lib/neo4j/rails/compositions.rb +9 -1
  37. data/lib/neo4j/rails/mapping/property.rb +27 -25
  38. data/lib/neo4j/rails/model.rb +1 -0
  39. data/lib/neo4j/rails/persistence.rb +56 -56
  40. data/lib/neo4j/rails/rel_persistence.rb +1 -1
  41. data/lib/neo4j/rails/relationship.rb +9 -4
  42. data/lib/neo4j/rails/relationships/relationships.rb +6 -2
  43. data/lib/neo4j/rails/relationships/rels_dsl.rb +58 -0
  44. data/lib/neo4j/rails/relationships/storage.rb +10 -1
  45. data/lib/neo4j/rails/validations/uniqueness.rb +1 -0
  46. data/lib/neo4j/rails/versioning/versioning.rb +64 -9
  47. data/lib/neo4j/rule/event_listener.rb +7 -1
  48. data/lib/neo4j/rule/functions/count.rb +6 -0
  49. data/lib/neo4j/rule/rule.rb +20 -5
  50. data/lib/neo4j/rule/rule_node.rb +31 -19
  51. data/lib/neo4j/traversal/traverser.rb +38 -0
  52. data/lib/neo4j/version.rb +1 -1
  53. data/neo4j.gemspec +1 -1
  54. metadata +24 -17
  55. data/lib/neo4j/jars/core/neo4j-backup-1.4.1.jar +0 -0
  56. data/lib/neo4j/jars/core/neo4j-index-1.3-1.3.M01.jar +0 -0
  57. data/lib/neo4j/jars/core/neo4j-kernel-1.4.1.jar +0 -0
  58. data/lib/neo4j/jars/ha/neo4j-com-1.4.1.jar +0 -0
  59. data/lib/neo4j/jars/ha/neo4j-ha-1.4.1.jar +0 -0
  60. data/lib/neo4j/jars/ha/neo4j-jmx-1.4.1.jar +0 -0
  61. data/lib/neo4j/jars/ha/neo4j-management-1.4.1.jar +0 -0
  62. data/lib/neo4j/jars/ha/netty-3.2.1.Final.jar +0 -0
@@ -66,8 +66,12 @@ module Neo4j
66
66
  # node.rels(:foo) #=> [node2] - incoming and outgoing
67
67
  #
68
68
  def rels(*rel_types)
69
- storage = _create_or_get_storage(rel_types.first)
70
- RelsDSL.new(storage)
69
+ if rel_types.empty?
70
+ AllRelsDsl.new(@_relationships, _java_node)
71
+ else
72
+ storage = _create_or_get_storage(rel_types.first)
73
+ RelsDSL.new(storage)
74
+ end
71
75
  end
72
76
 
73
77
  def add_outgoing_rel(rel_type, rel) #:nodoc:
@@ -2,6 +2,55 @@ module Neo4j
2
2
  module Rails
3
3
  module Relationships
4
4
 
5
+ # This DSL is return when asking for all relationship from and to a node, example node.rels.each{}
6
+ #
7
+ class AllRelsDsl
8
+ include Enumerable
9
+
10
+ def initialize(rels_stores, node)
11
+ @rels_stores = rels_stores
12
+ @node = node
13
+ end
14
+
15
+ def each
16
+ @rels_stores.each_value {|storage| storage.relationships(:both).each{|r| yield r}}
17
+ @node && @node.rels.each {|r| yield r}
18
+ end
19
+
20
+ # simply traverse and count all relationship
21
+ def size
22
+ s = 0
23
+ each { |_| s += 1 }
24
+ s
25
+ end
26
+
27
+ # Find all relationships between two nodes like this *if* the node is persisted.
28
+ # Returns an Enumerable. If the node is not persisted it will raise an error.
29
+ # Notice, only persisted relationships will be returned.
30
+ def to_other(other)
31
+ raise('node.rels(...).to_other() not allowed on a node that is not persisted') unless @node
32
+ @node.rels.to_other(other)
33
+ end
34
+
35
+ def delete_all
36
+ # since some of the relationships might not be a Neo4j::Rails::Relationship we must create a transaction
37
+ Neo4j::Transaction.run do
38
+ each{|r| r.respond_to?(:delete) ? r.delete : r.del}
39
+ end
40
+ @rels_stores.clear
41
+ end
42
+
43
+ def destroy_all
44
+ Neo4j::Transaction.run do
45
+ each{|r| r.respond_to?(:destroy)? r.destroy : r.del}
46
+ end
47
+ @rels_stores.clear
48
+ end
49
+
50
+ alias_method :del, :delete_all
51
+ end
52
+
53
+
5
54
  # Instances of this class is returned from the #rels, and generated accessor methods:
6
55
  # has_n and has_one.
7
56
  # Notice, this class is very similar to the Neo4j::Rails::Relationships::NodesDSL except that
@@ -42,6 +91,13 @@ module Neo4j
42
91
  rel
43
92
  end
44
93
 
94
+ # Find all relationships between two nodes like this *if* the node is persisted.
95
+ # Returns an Enumerable. If the node is not persisted it will raise an error.
96
+ # Notice, only persisted relationships will be returned.
97
+ def to_other(other)
98
+ @storage.to_other(other)
99
+ end
100
+
45
101
  # Connects this node with an already existing other node with a new relationship.
46
102
  # The relationship can optionally be given a hash of properties
47
103
  # Does not save it.
@@ -98,11 +154,13 @@ module Neo4j
98
154
  # Destroys all relationships object. Will not destroy the nodes.
99
155
  def destroy_all
100
156
  each {|n| n.destroy}
157
+ @storage.clear_unpersisted
101
158
  end
102
159
 
103
160
  # Delete all relationship.
104
161
  def delete_all
105
162
  each {|n| n.delete}
163
+ @storage.clear_unpersisted
106
164
  end
107
165
 
108
166
  # Same as Neo4j::Rails::Relationships::NodesDSL#find except that it searches the relationships instead of
@@ -23,6 +23,11 @@ module Neo4j
23
23
  "Storage #{object_id} node: #{@node.id} rel_type: #{@rel_type} outgoing #{@outgoing_rels.size} incoming #{@incoming_rels.size}"
24
24
  end
25
25
 
26
+ def clear_unpersisted
27
+ @outgoing_rels.clear
28
+ @incoming_rels.clear
29
+ end
30
+
26
31
  def remove_from_identity_map
27
32
  @outgoing_rels.each {|r| Neo4j::IdentityMap.remove(r._java_rel)}
28
33
  @incoming_rels.each {|r| Neo4j::IdentityMap.remove(r._java_rel)}
@@ -37,6 +42,10 @@ module Neo4j
37
42
  counter
38
43
  end
39
44
 
45
+ def to_other(other)
46
+ (@node._java_node) ? @node._java_node.rels(@rel_type).to_other(other) : raise('node.rels(...).to_other() not allowed on a node that is not persisted')
47
+ end
48
+
40
49
  def build(attrs)
41
50
  @target_class.new(attrs)
42
51
  end
@@ -172,7 +181,7 @@ module Neo4j
172
181
  end
173
182
 
174
183
  in_rels.each do |rel|
175
- rel.start_node.rm_outgoing_rel(@rel_type.to_sym, rel)
184
+ rel.start_node.rm_outgoing_rel(@rel_type.to_sym, rel) if rel.start_node
176
185
  success = rel.persisted? || rel.save
177
186
  # don't think this can happen - just in case, TODO
178
187
  raise "Can't save incoming #{rel}, validation errors ? #{rel.errors.inspect}" unless success
@@ -54,6 +54,7 @@ module Neo4j
54
54
  end
55
55
 
56
56
  def self.query(model,attribute,value)
57
+ value = value.gsub("\"", "\\\"") if !value.blank?
57
58
  value.blank? ? model.all("*:* -#{attribute}:[* TO *]", :type => :fulltext) : model.all("#{attribute}: \"#{value}\"", :type => :fulltext)
58
59
  end
59
60
 
@@ -45,6 +45,16 @@ module Neo4j
45
45
  class Snapshot
46
46
  include Neo4j::NodeMixin
47
47
 
48
+ def assign(key,value)
49
+ @converted_properties = {} if @converted_properties.nil?
50
+ @converted_properties[key.to_sym] = value
51
+ end
52
+
53
+ def [](key)
54
+ return @converted_properties[key] if @converted_properties
55
+ super(key)
56
+ end
57
+
48
58
  def incoming(rel_type)
49
59
  super "version_#{rel_type.to_s}".to_sym
50
60
  end
@@ -70,7 +80,9 @@ module Neo4j
70
80
  # @param [ Integer ] number The version number to retrieve.
71
81
  # Returns nil in case a version is not found.
72
82
  def version(number)
73
- Version.find(:model_classname => _classname, :instance_id => neo_id, :number => number) {|query| query.first.nil? ? nil : query.first.end_node}
83
+ snapshot = Version.find(:model_classname => _classname, :instance_id => neo_id, :number => number) {|query| query.first.nil? ? nil : query.first.end_node}
84
+ snapshot.props.each_pair{|k,v| snapshot.assign(k,Neo4j::TypeConverters.to_ruby(self.class, k, v))} if !snapshot.nil?
85
+ snapshot
74
86
  end
75
87
 
76
88
  ##
@@ -83,40 +95,83 @@ module Neo4j
83
95
  end
84
96
  end
85
97
 
98
+ ##
99
+ # Reverts this instance to a specified version
100
+ # @param [ Integer ] version_number The version number to revert to.
101
+ # Reverting the instance will increment the current version number.
102
+ def revert_to(version_number)
103
+ snapshot = version(version_number)
104
+ self.props.each_pair{|k,v| self[k] = nil if !snapshot.props.has_key?(k)}
105
+ snapshot.props.each_pair{|k,v| self[k] = v if self.props[k].nil?}
106
+ Neo4j::Transaction.run do
107
+ restore_relationships(snapshot)
108
+ save
109
+ end
110
+ end
111
+
86
112
  private
87
113
  def revise
88
114
  Neo4j::Transaction.run do
89
- snapshot = Snapshot.new(self.props.reject{|key, value| key.to_sym == :_classname})
90
- version_relationships(snapshot)
115
+ snapshot = Snapshot.new(converted_properties)
116
+ each_versionable_relationship{|rel| create_version_relationship(rel,snapshot)}
91
117
  delete_old_version if version_max.present? && number_of_versions >= version_max
92
118
  Version.new(:version, self, snapshot, :model_classname => _classname, :instance_id => neo_id, :number => current_version)
93
119
  end
94
120
  end
95
121
 
122
+ def converted_properties
123
+ properties = self.props.reject{|key, value| key.to_sym == :_classname}
124
+ properties.inject({}) { |h,(k,v)| h[k] = Neo4j::TypeConverters.to_java(self.class, k, v); h }
125
+ end
126
+
96
127
  def number_of_versions
97
128
  Version.find(:model_classname => _classname, :instance_id => neo_id) {|query| query.size}
98
129
  end
99
130
 
100
- def version_relationships(snapshot)
131
+ def each_versionable_relationship
132
+ rule_relationships = java.util.HashSet.new(Neo4j::Rule::Rule.rule_names_for(_classname))
101
133
  self._java_node.getRelationships().each do |rel|
102
- if (self._java_node == rel.getStartNode())
103
- snapshot._java_node.createRelationshipTo(rel.getEndNode(), relationship_type(rel.getType()))
104
- else
105
- rel.getStartNode().createRelationshipTo(snapshot._java_node, relationship_type(rel.getType()))
106
- end
134
+ yield rel unless rule_relationships.contains(rel.getType().name().to_sym) || rel.getType.name.to_sym == :version
107
135
  end
108
136
  end
109
137
 
138
+ def create_version_relationship(rel,snapshot)
139
+ create_relationship(self._java_node,snapshot._java_node, rel, relationship_type(rel.getType()))
140
+ end
141
+
110
142
  def relationship_type(rel_type)
111
143
  org.neo4j.graphdb.DynamicRelationshipType.withName( "version_#{rel_type.name}" )
112
144
  end
113
145
 
146
+ def restore_relationship_type(snapshot_rel_type)
147
+ org.neo4j.graphdb.DynamicRelationshipType.withName( "#{snapshot_rel_type.name.gsub("version_","")}" )
148
+ end
149
+
114
150
  def delete_old_version
115
151
  versions = Version.find(:model_classname => _classname).asc(:number)
116
152
  versions.first.del
117
153
  versions.close
118
154
  end
119
155
 
156
+ def restore_relationships(snapshot)
157
+ each_versionable_relationship{|rel| rel.del}
158
+ snapshot._java_node.getRelationships().each do |rel|
159
+ restore_relationship(rel,snapshot) unless rel.getType.name.to_sym == :version
160
+ end
161
+ end
162
+
163
+ def restore_relationship(rel,snapshot)
164
+ create_relationship(snapshot._java_node, self._java_node, rel, restore_relationship_type(rel.getType()))
165
+ end
166
+
167
+ def create_relationship(comparison_node,connection_node,rel, relationship_type)
168
+ if (comparison_node == rel.getStartNode())
169
+ connection_node.createRelationshipTo(rel.getEndNode(), relationship_type)
170
+ else
171
+ rel.getStartNode().createRelationshipTo(connection_node, relationship_type)
172
+ end
173
+ end
174
+
120
175
  module ClassMethods #:nodoc:
121
176
 
122
177
  # Sets the maximum number of versions to store.
@@ -30,7 +30,7 @@ module Neo4j
30
30
 
31
31
  id = node.getId
32
32
  rule_node.rules.each do |rule|
33
- next if rule.functions.nil?
33
+ next if rule.functions.nil? || rule.bulk_update?
34
34
  rule_name = rule.rule_name.to_s
35
35
 
36
36
  # is the rule node deleted ?
@@ -45,6 +45,12 @@ module Neo4j
45
45
  end
46
46
  end
47
47
 
48
+ def classes_changed(changed_class_map)
49
+ changed_class_map.each_pair do |clazz,class_change|
50
+ Rule.bulk_trigger_rules(clazz,class_change,changed_class_map)
51
+ end
52
+ end
53
+
48
54
  def on_neo4j_started(db)
49
55
  if not Neo4j::Config[:enable_rules]
50
56
  db.event_handler.remove(self)
@@ -28,6 +28,12 @@ module Neo4j
28
28
  # we are only counting, not interested in property changes
29
29
  end
30
30
 
31
+ def classes_changed(rule_name, rule_node, class_change)
32
+ key = rule_node_property(rule_name)
33
+ rule_node[key] ||= 0
34
+ rule_node[key] += class_change.net_change
35
+ end
36
+
31
37
  def self.function_name
32
38
  :count
33
39
  end
@@ -24,6 +24,7 @@ module Neo4j
24
24
  @triggers = [@triggers] if @triggers && !@triggers.respond_to?(:each)
25
25
  @functions = [@functions] if @functions && !@functions.respond_to?(:each)
26
26
  @filter = block
27
+ @bulk_update = !@functions.nil? && @functions.size == 1 && @functions.first.class.function_name == :count && @filter.nil?
27
28
  end
28
29
 
29
30
  def to_s
@@ -58,6 +59,10 @@ module Neo4j
58
59
  end
59
60
  end
60
61
 
62
+ def bulk_update?
63
+ @bulk_update
64
+ end
65
+
61
66
  # ------------------------------------------------------------------------------------------------------------------
62
67
  # Class Methods
63
68
  # ------------------------------------------------------------------------------------------------------------------
@@ -74,7 +79,7 @@ module Neo4j
74
79
  def has_rules?(clazz)
75
80
  !@rule_nodes[clazz.to_s].nil?
76
81
  end
77
-
82
+
78
83
  def rule_names_for(clazz)
79
84
  rule_node = rule_node_for(clazz)
80
85
  rule_node.rules.map { |rule| rule.rule_name }
@@ -105,7 +110,7 @@ module Neo4j
105
110
 
106
111
  def trigger?(node)
107
112
  classname = node[:_classname]
108
- @rule_nodes && classname && rule_node_for(classname)
113
+ @rule_nodes && classname && rule_node_for(classname) && !rule_node_for(classname).bulk_update?
109
114
  end
110
115
 
111
116
  def trigger_rules(node, *changes)
@@ -118,15 +123,25 @@ module Neo4j
118
123
  recursive(node,rule_node.model_class,*changes)
119
124
  end
120
125
 
121
- private
126
+ def bulk_trigger_rules(classname,class_change, map)
127
+ rule_node = rule_node_for(classname)
128
+ rule_node.classes_changed(class_change)
129
+ if (clazz = rule_node.model_class.superclass) && clazz.include?(Neo4j::NodeMixin)
130
+ bulk_trigger_rules(clazz.name,class_change,map) if clazz != Neo4j::Rails::Model
131
+ end
132
+ end
133
+
134
+ private
122
135
 
123
- def recursive(node,model_class,*changes)
124
- if (clazz = model_class.superclass) && clazz.include?(Neo4j::NodeMixin)
136
+ def recursive(node,model_class,*changes)
137
+ if (clazz = model_class.superclass) && clazz.include?(Neo4j::NodeMixin)
138
+ if clazz != Neo4j::Rails::Model
125
139
  rule_node = rule_node_for(clazz)
126
140
  rule_node && rule_node.execute_rules(node, *changes)
127
141
  recursive(node,clazz,*changes)
128
142
  end
129
143
  end
144
+ end
130
145
  end
131
146
  end
132
147
  end
@@ -10,6 +10,7 @@ module Neo4j
10
10
  include ToJava
11
11
  attr_reader :rules
12
12
  attr_reader :model_class
13
+ @@rule_nodes = {}
13
14
 
14
15
  def initialize(clazz)
15
16
  @model_class = eval("#{clazz}")
@@ -27,7 +28,21 @@ module Neo4j
27
28
  def node_exist?
28
29
  !ref_node.rel?(@classname)
29
30
  end
30
-
31
+
32
+ def rule_node
33
+ ref_node._java_node.synchronized do
34
+ @@rule_nodes[key] ||= find_node || create_node
35
+ end
36
+ end
37
+
38
+ def rule_node?(node)
39
+ @@rule_nodes[key] == node
40
+ end
41
+
42
+ def key
43
+ "#{ref_node}#{@ref_node_key}".to_sym
44
+ end
45
+
31
46
  def ref_node
32
47
  if @model_class.respond_to? :ref_node_for_class
33
48
  @model_class.ref_node_for_class
@@ -61,11 +76,6 @@ module Neo4j
61
76
  ref_node.rel?(@classname.to_s) && ref_node._rel(:outgoing, @classname.to_s)._end_node
62
77
  end
63
78
 
64
- def rule_node
65
- clear_rule_node if ref_node_changed?
66
- Thread.current[@rule_node_key] ||= find_node || create_node
67
- end
68
-
69
79
  def ref_node_changed?
70
80
  if ref_node != Thread.current[@ref_node_key]
71
81
  Thread.current[@ref_node_key] = ref_node
@@ -75,16 +85,8 @@ module Neo4j
75
85
  end
76
86
  end
77
87
 
78
- def rule_node?(node)
79
- cached_rule_node == node
80
- end
81
-
82
- def cached_rule_node
83
- Thread.current[@rule_node_key]
84
- end
85
-
86
88
  def clear_rule_node
87
- Thread.current[@rule_node_key] = nil
89
+ @@rule_nodes[key] = nil
88
90
  end
89
91
 
90
92
  def rule_names
@@ -186,7 +188,7 @@ module Neo4j
186
188
  end
187
189
 
188
190
  def connect(rule_name, end_node)
189
- rule_node.outgoing(rule_name) << end_node
191
+ rule_node._java_node.createRelationshipTo(end_node._java_node, org.neo4j.graphdb.DynamicRelationshipType.withName(rule_name))
190
192
  end
191
193
 
192
194
  # sever a direct one-to-one relationship if it exists
@@ -196,9 +198,19 @@ module Neo4j
196
198
  !rel.nil?
197
199
  end
198
200
 
199
- end
200
-
201
+ def bulk_update?
202
+ @rules.size == 1 && @rules.first.bulk_update?
203
+ end
201
204
 
205
+ def classes_changed(total)
206
+ @rules.each do |rule|
207
+ if rule.bulk_update?
208
+ rule.functions.first.classes_changed(rule.rule_name, rule_node, total)
209
+ total.added.each{|node| connect(rule.rule_name, node)}
210
+ total.deleted.each{|node| break_connection(rule.rule_name, node)}
211
+ end
212
+ end
213
+ end
214
+ end
202
215
  end
203
-
204
216
  end