neo4j 1.2.6-java → 1.3.0-java

Sign up to get free protection for your applications and to get access to all the features.
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