neo4j 1.0.0.beta.28-java → 1.0.0.beta.29-java

Sign up to get free protection for your applications and to get access to all the features.
data/CONTRIBUTORS CHANGED
@@ -2,6 +2,7 @@ Maintainer:
2
2
  Andreas Ronge <andreas dot ronge at gmail dot com>
3
3
 
4
4
  Contributors:
5
+ * Stephan Hagemann
5
6
  * Bobby Calderwood
6
7
  * Ben Jackson
7
8
  * Dwight van Tuyl
data/bin/neo4j-shell CHANGED
@@ -1,107 +1,5 @@
1
- #!/bin/sh
2
- # ----------------------------------------------------------------------------
3
- # Copyright 2001-2006 The Apache Software Foundation.
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- # ----------------------------------------------------------------------------
1
+ #!/usr/bin/env ruby
17
2
 
18
- # Copyright (c) 2001-2002 The Apache Software Foundation. All rights
19
- # reserved.
20
-
21
- BASEDIR=`dirname $0`/..
22
- BASEDIR=`(cd "$BASEDIR"; pwd)`
23
-
24
-
25
-
26
- # OS specific support. $var _must_ be set to either true or false.
27
- cygwin=false;
28
- darwin=false;
29
- case "`uname`" in
30
- CYGWIN*) cygwin=true ;;
31
- Darwin*) darwin=true
32
- if [ -z "$JAVA_VERSION" ] ; then
33
- JAVA_VERSION="CurrentJDK"
34
- else
35
- echo "Using Java version: $JAVA_VERSION"
36
- fi
37
- if [ -z "$JAVA_HOME" ] ; then
38
- JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home
39
- fi
40
- ;;
41
- esac
42
-
43
- if [ -z "$JAVA_HOME" ] ; then
44
- if [ -r /etc/gentoo-release ] ; then
45
- JAVA_HOME=`java-config --jre-home`
46
- fi
47
- fi
48
-
49
- # For Cygwin, ensure paths are in UNIX format before anything is touched
50
- if $cygwin ; then
51
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
52
- [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
53
- fi
54
-
55
- # If a specific java binary isn't specified search for the standard 'java' binary
56
- if [ -z "$JAVACMD" ] ; then
57
- if [ -n "$JAVA_HOME" ] ; then
58
- if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
59
- # IBM's JDK on AIX uses strange locations for the executables
60
- JAVACMD="$JAVA_HOME/jre/sh/java"
61
- else
62
- JAVACMD="$JAVA_HOME/bin/java"
63
- fi
64
- else
65
- JAVACMD=`which java`
66
- fi
67
- fi
68
-
69
- if [ ! -x "$JAVACMD" ] ; then
70
- echo "Error: JAVA_HOME is not defined correctly."
71
- echo " We cannot execute $JAVACMD"
72
- exit 1
73
- fi
74
-
75
- if [ -z "$REPO" ]
76
- then
77
- REPO="$BASEDIR"/lib/neo4j/jars
78
- fi
79
-
80
- LIBRARY_JARS=""
81
- for jar in $(find $REPO -iname "*.jar")
82
- do
83
- LIBRARY_JARS=${LIBRARY_JARS}:$jar
84
- done
85
-
86
- CLASSPATH=$CLASSPATH_PREFIX${LIBRARY_JARS}
87
-
88
- EXTRA_JVM_ARGUMENTS=""
89
-
90
- # For Cygwin, switch paths to Windows format before running java
91
- if $cygwin; then
92
- [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
93
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
94
- [ -n "$HOME" ] && HOME=`cygpath --path --windows "$HOME"`
95
- [ -n "$BASEDIR" ] && BASEDIR=`cygpath --path --windows "$BASEDIR"`
96
- [ -n "$REPO" ] && REPO=`cygpath --path --windows "$REPO"`
97
- fi
98
-
99
- exec "$JAVACMD" $JAVA_OPTS \
100
- $EXTRA_JVM_ARGUMENTS \
101
- -classpath "$CLASSPATH" \
102
- -Dapp.name="neo4j-shell" \
103
- -Dapp.pid="$$" \
104
- -Dapp.repo="$REPO" \
105
- -Dbasedir="$BASEDIR" \
106
- org.neo4j.shell.StartClient \
107
- "$@"
3
+ require 'neo4j'
4
+ Neo4j.load_shell_jars
5
+ org.neo4j.shell.StartClient.main(ARGV)
data/lib/neo4j.rb CHANGED
@@ -15,6 +15,7 @@ require 'neo4j/jars/core/geronimo-jta_1.1_spec-1.1.1.jar'
15
15
  require 'neo4j/jars/core/lucene-core-3.0.3.jar'
16
16
  require 'neo4j/jars/core/neo4j-lucene-index-0.5-1.3.M01.jar'
17
17
  require 'neo4j/jars/core/neo4j-kernel-1.3-1.3.M01.jar'
18
+ require 'neo4j/jars/ha/neo4j-management-1.3-1.3.M01.jar'
18
19
 
19
20
  module Neo4j
20
21
 
@@ -24,11 +25,13 @@ module Neo4j
24
25
  require 'neo4j/jars/core/neo4j-index-1.3-1.3.M01.jar'
25
26
  end
26
27
 
28
+ def self.load_shell_jars
29
+ require 'neo4j/jars/ha/neo4j-shell-1.3-1.3.M01.jar'
30
+ end
31
+
27
32
  def self.load_ha_jars
28
33
  require 'neo4j/jars/ha/log4j-1.2.16.jar'
29
34
  require 'neo4j/jars/ha/neo4j-ha-0.6-1.3.M01.jar'
30
- require 'neo4j/jars/ha/neo4j-management-1.3-1.3.M01.jar'
31
- require 'neo4j/jars/ha/neo4j-shell-1.3-1.3.M01.jar'
32
35
  require 'neo4j/jars/ha/netty-3.2.1.Final.jar'
33
36
  require 'neo4j/jars/ha/org.apache.servicemix.bundles.jline-0.9.94_1.jar'
34
37
  require 'neo4j/jars/ha/org.apache.servicemix.bundles.lucene-3.0.1_2.jar'
@@ -1,2 +1,4 @@
1
1
  require 'neo4j/batch/inserter'
2
2
  require 'neo4j/batch/indexer'
3
+ require 'neo4j/batch/rule_inserter'
4
+ require 'neo4j/batch/rule_node'
@@ -23,6 +23,7 @@ module Neo4j
23
23
  raise "Not allowed to start batch inserter while Neo4j is already running at storage location #{storage_path}" if Neo4j.storage_path == storage_path
24
24
  @batch_inserter = org.neo4j.kernel.impl.batchinsert.BatchInserterImpl.new(storage_path, config)
25
25
  Indexer.index_provider = org.neo4j.index.impl.lucene.LuceneBatchInserterIndexProvider.new(@batch_inserter)
26
+ @rule_inserter = RuleInserter.new(self)
26
27
  end
27
28
 
28
29
  def running?
@@ -33,7 +34,8 @@ module Neo4j
33
34
  def shutdown
34
35
  @batch_inserter && @batch_inserter.shutdown
35
36
  @batch_inserter = nil
36
-
37
+ @rule_inserter = nil
38
+
37
39
  Indexer.index_provider
38
40
  Indexer.index_provider && Indexer.index_provider.shutdown
39
41
  Indexer.index_provider = nil
@@ -48,6 +50,7 @@ module Neo4j
48
50
 
49
51
  node = @batch_inserter.create_node(props)
50
52
  props && _index(node, props, clazz)
53
+ @rule_inserter.node_added(node, props)
51
54
  node
52
55
  end
53
56
 
@@ -0,0 +1,24 @@
1
+ module Neo4j
2
+ module Batch
3
+ class RuleInserter #:nodoc:
4
+ def initialize(inserter)
5
+ @inserter = inserter
6
+ end
7
+
8
+ def node_added(node, props)
9
+ classname = props && props['_classname']
10
+ classname && create_rules(node, props, classname)
11
+ end
12
+
13
+
14
+ def create_rules(node, props, classname)
15
+ rule_node = RuleNode.rule_node_for(classname, @inserter)
16
+ rule_node && rule_node.execute_rules(@inserter, node, props)
17
+
18
+ if (clazz = eval("#{classname}.superclass")) && clazz.include?(Neo4j::NodeMixin)
19
+ create_rules(node, props, clazz.to_s)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,72 @@
1
+ module Neo4j
2
+ module Batch
3
+ class RuleNode #:nodoc:
4
+ attr_reader :node
5
+ delegate :rules, :to => :@wrapped_rule_node
6
+
7
+ def initialize(wrapped_rule_node, node)
8
+ @wrapped_rule_node = wrapped_rule_node
9
+ @node = node
10
+ end
11
+
12
+ def execute_rules(inserter, node, props)
13
+ rules.each do |rule|
14
+ if execute_filter(rule, props)
15
+ inserter.create_rel(rule.rule_name, @node, node)
16
+ execute_add_functions(inserter, rule, props)
17
+ end
18
+ end
19
+ end
20
+
21
+ def execute_add_functions(inserter, rule, props)
22
+ rule_props = nil
23
+ executed_functions = []
24
+ props.keys.each do |key|
25
+ functions = rule.functions_for(key)
26
+ next unless functions
27
+ functions -= executed_functions
28
+ rule_props ||= clone_node_props(inserter) #inserter.node_props(@node)
29
+ functions.each { |f| executed_functions << f; f.add(rule.rule_name, rule_props, props[key]) }
30
+ end
31
+ rule_props && inserter.set_node_props(@node, rule_props)
32
+ end
33
+
34
+ def clone_node_props(inserter)
35
+ hash = {}
36
+ props = inserter.node_props(@node) # need to clone this since we can't modify it
37
+ props.each_pair{|k,v| hash[k]=v}
38
+ hash
39
+ end
40
+
41
+ def execute_filter(rule, props)
42
+ if rule.filter.nil?
43
+ true
44
+ elsif rule.filter.arity != 1
45
+ classname = props['_classname'] || 'Neo4j::Node'
46
+ clazz = Neo4j::Node.to_class(classname)
47
+ wrapper = clazz.load_wrapper(ActiveSupport::HashWithIndifferentAccess.new(props))
48
+ wrapper.instance_eval(&rule.filter)
49
+ else
50
+ rule.filter.call(ActiveSupport::HashWithIndifferentAccess.new(props))
51
+ end
52
+ end
53
+
54
+ class << self
55
+ def rule_node_for(classname, inserter)
56
+ return nil unless Neo4j::Rule::Rule.has_rules?(classname)
57
+ wrapped_rule_node = Neo4j::Rule::Rule.rule_node_for(classname)
58
+ @rule_nodes ||= {}
59
+ @rule_nodes[classname] ||= RuleNode.new(wrapped_rule_node, create_node(classname, inserter))
60
+ end
61
+
62
+ def create_node(classname, inserter)
63
+ rule_node = inserter.create_node
64
+ inserter.create_rel(classname, inserter.ref_node, rule_node)
65
+ rule_node
66
+ end
67
+ end
68
+
69
+
70
+ end
71
+ end
72
+ end
@@ -22,6 +22,12 @@ module Neo4j
22
22
  @running = true
23
23
  @storage_path = Config.storage_path
24
24
 
25
+
26
+ if Config[:enable_remote_shell]
27
+ Neo4j.logger.info("Enable remote shell at port #{Config[:enable_remote_shell]}")
28
+ Neo4j.load_shell_jars
29
+ end
30
+
25
31
  begin
26
32
  if self.class.locked?
27
33
  start_readonly_graph_db
@@ -96,10 +102,17 @@ module Neo4j
96
102
  @graph = nil
97
103
  @lucene = nil
98
104
  @running = false
105
+ @neo4j_manager = nil
99
106
  end
100
107
 
101
108
  end
102
109
 
110
+
111
+ def management(jmx_clazz) #:nodoc:
112
+ @neo4j_manager ||= org.neo4j.management.Neo4jManager.new(@graph.get_management_bean(org.neo4j.management.Kernel.java_class))
113
+ @neo4j_manager.getBean(jmx_clazz.java_class)
114
+ end
115
+
103
116
  def begin_tx #:nodoc:
104
117
  @graph.begin_tx
105
118
  end
@@ -48,7 +48,7 @@ module Neo4j
48
48
 
49
49
  # The node that holds the db version property
50
50
  def migration_meta_node
51
- Neo4j::Rule::RuleEventListener.rule_node_for(self).rule_node
51
+ Neo4j::Rule::Rule.rule_node_for(self).rule_node
52
52
  end
53
53
 
54
54
  # Remote all migration and set migrate_to = nil and set the current version to nil
data/lib/neo4j/neo4j.rb CHANGED
@@ -110,6 +110,33 @@ module Neo4j
110
110
  this_db.graph.reference_node
111
111
  end
112
112
 
113
+ # Returns a Management JMX Bean.
114
+ #
115
+ # Notice that this information is also provided by the jconsole Java tool, check http://wiki.neo4j.org/content/Monitoring_and_Deployment
116
+ # and http://docs.neo4j.org/chunked/milestone/operations-monitoring.html
117
+ #
118
+ # By default it returns the Primitivies JMX Bean that can be used to find number of nodes in use.
119
+ #
120
+ # ==== Example Neo4j Primititives
121
+ #
122
+ # Neo4j.management.get_number_of_node_ids_in_use
123
+ # Neo4j.management.getNumberOfPropertyIdsInUse
124
+ # Neo4j.management.getNumberOfRelationshipIdsInUse
125
+ # Neo4j.management.get_number_of_relationship_type_ids_in_use
126
+ #
127
+ # ==== Example Neo4j HA Cluster Info
128
+ #
129
+ # Neo4j.management(org.neo4j.management.HighAvailability).isMaster
130
+ #
131
+ # ==== Arguments
132
+ #
133
+ # jmx_clazz :: http://api.neo4j.org/current/org/neo4j/management/package-summary.html
134
+ # this_db :: default currently runnig instance or a newly started neo4j db instance
135
+ #
136
+ def management(jmx_clazz = org.neo4j.management.Primitives, this_db = self.started_db)
137
+ this_db.management(jmx_clazz)
138
+ end
139
+
113
140
  # Returns an Enumerable object for all nodes in the database
114
141
  def all_nodes(this_db = self.started_db)
115
142
  Enumerator.new(this_db, :each_node)
@@ -78,7 +78,7 @@ module Neo4j
78
78
 
79
79
  # Trigger rules.
80
80
  # You don't normally need to call this method (except in Migration) since
81
- # it will be triggered automatically by the Neo4j::Rule::RuleEventListener
81
+ # it will be triggered automatically by the Neo4j::Rule::Rule
82
82
  #
83
83
  def trigger_rules
84
84
  self.class.trigger_rules(self)
@@ -64,7 +64,7 @@ module Neo4j
64
64
  self[key] = value
65
65
  end
66
66
  end
67
- keys_to_delete.each { |key| delete_property(key) } if strict
67
+ keys_to_delete.each { |key| remove_property(key) } if strict
68
68
  self
69
69
  end
70
70
 
@@ -57,7 +57,101 @@ module Neo4j
57
57
  # Mass-assign attributes. Stops any protected attributes from being assigned.
58
58
  def attributes=(attributes, guard_protected_attributes = true)
59
59
  attributes = sanitize_for_mass_assignment(attributes) if guard_protected_attributes
60
- attributes.each { |k, v| respond_to?("#{k}=") ? send("#{k}=", v) : self[k] = v }
60
+
61
+ multi_parameter_attributes = []
62
+ attributes.each do |k, v|
63
+ if k.to_s.include?("(")
64
+ multi_parameter_attributes << [ k, v ]
65
+ else
66
+ respond_to?("#{k}=") ? send("#{k}=", v) : self[k] = v
67
+ end
68
+ end
69
+
70
+ assign_multiparameter_attributes(multi_parameter_attributes)
71
+ end
72
+
73
+ # Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
74
+ # by calling new on the column type or aggregation type (through composed_of) object with these parameters.
75
+ # So having the pairs written_on(1) = "2004", written_on(2) = "6", written_on(3) = "24", will instantiate
76
+ # written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
77
+ # parentheses to have the parameters typecasted before they're used in the constructor. Use i for Fixnum,
78
+ # f for Float, s for String, and a for Array. If all the values for a given attribute are empty, the
79
+ # attribute will be set to nil.
80
+ def assign_multiparameter_attributes(pairs)
81
+ execute_callstack_for_multiparameter_attributes(
82
+ extract_callstack_for_multiparameter_attributes(pairs)
83
+ )
84
+ end
85
+
86
+ def execute_callstack_for_multiparameter_attributes(callstack)
87
+ errors = []
88
+ callstack.each do |name, values_with_empty_parameters|
89
+ begin
90
+ # (self.class.reflect_on_aggregation(name.to_sym) || column_for_attribute(name)).klass
91
+ klass = self.class._decl_props[name.to_sym][:type]
92
+ raise "Not a multiparameter attribute, missing :type on property #{name} for #{self.class}" unless klass
93
+
94
+ # in order to allow a date to be set without a year, we must keep the empty values.
95
+ values = values_with_empty_parameters.reject { |v| v.nil? }
96
+
97
+ if values.empty?
98
+ send(name + "=", nil)
99
+ else
100
+
101
+ value = if Time == klass
102
+ instantiate_time_object(name, values)
103
+ elsif Date == klass
104
+ begin
105
+ values = values_with_empty_parameters.collect do |v| v.nil? ? 1 : v end
106
+ Date.new(*values)
107
+ rescue ArgumentError => ex # if Date.new raises an exception on an invalid date
108
+ instantiate_time_object(name, values).to_date # we instantiate Time object and convert it back to a date thus using Time's logic in handling invalid dates
109
+ end
110
+ else
111
+ klass.new(*values)
112
+ end
113
+
114
+ send(name + "=", value)
115
+ end
116
+ rescue Exception => ex
117
+ raise "error on assignment #{values.inspect} to #{name}, ex: #{ex}"
118
+ end
119
+ end
120
+ unless errors.empty?
121
+ raise MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes"
122
+ end
123
+ end
124
+
125
+ def instantiate_time_object(name, values)
126
+ # if self.class.send(:create_time_zone_conversion_attribute?, name, column_for_attribute(name))
127
+ # Time.zone.local(*values)
128
+ # else
129
+ Time.time_with_datetime_fallback(self.class.default_timezone, *values)
130
+ # end
131
+ end
132
+
133
+ def extract_callstack_for_multiparameter_attributes(pairs)
134
+ attributes = { }
135
+
136
+ for pair in pairs
137
+ multiparameter_name, value = pair
138
+ attribute_name = multiparameter_name.split("(").first
139
+ attributes[attribute_name] = [] unless attributes.include?(attribute_name)
140
+
141
+ parameter_value = value.empty? ? nil : type_cast_attribute_value(multiparameter_name, value)
142
+ attributes[attribute_name] << [ find_parameter_position(multiparameter_name), parameter_value ]
143
+ end
144
+
145
+ attributes.each { |name, values| attributes[name] = values.sort_by{ |v| v.first }.collect { |v| v.last } }
146
+ end
147
+
148
+
149
+ def type_cast_attribute_value(multiparameter_name, value)
150
+ multiparameter_name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value
151
+ end
152
+
153
+ def find_parameter_position(multiparameter_name)
154
+ multiparameter_name.scan(/\(([0-9]*).*\)/).first.first
61
155
  end
62
156
 
63
157
  # Tracks the current changes and clears the changed attributes hash. Called
@@ -2,10 +2,10 @@ module Neo4j
2
2
  module Rails
3
3
  class Model
4
4
  include Neo4j::NodeMixin
5
-
5
+
6
6
  # Initialize a Node with a set of properties (or empty if nothing is passed)
7
7
  def initialize(attributes = {})
8
- reset_attributes
8
+ reset_attributes
9
9
  clear_relationships
10
10
  self.attributes = attributes if attributes.is_a?(Hash)
11
11
  end
@@ -39,9 +39,10 @@ module Neo4j
39
39
  end
40
40
 
41
41
  def ==(other)
42
- new? ? self.__id__ == other.__id__ : @_java_node == (other)
42
+ new? ? self.__id__ == other.__id__ : @_java_node == (other)
43
43
  end
44
-
44
+
45
+
45
46
  # --------------------------------------
46
47
  # Public Class Methods
47
48
  # --------------------------------------
@@ -49,11 +50,22 @@ module Neo4j
49
50
  # NodeMixin overwrites the #new class method but it saves it as orig_new
50
51
  # Here, we just get it back to normal
51
52
  alias :new :orig_new
52
-
53
+
53
54
  def transaction(&block)
54
55
  Neo4j::Rails::Transaction.run do |tx|
55
56
  block.call(tx)
56
- end
57
+ end
58
+ end
59
+
60
+ ##
61
+ # Determines whether to use Time.local (using :local) or Time.utc (using :utc) when pulling
62
+ # dates and times from the database. This is set to :local by default.
63
+ def default_timezone
64
+ @default_timezone || :local
65
+ end
66
+
67
+ def default_timezone=(zone)
68
+ @default_timezone = zone
57
69
  end
58
70
 
59
71
  def accepts_nested_attributes_for(*attr_names)
@@ -87,19 +99,19 @@ module Neo4j
87
99
  end
88
100
  end
89
101
  end
90
-
102
+
91
103
  Model.class_eval do
92
- extend ActiveModel::Translation
93
-
94
- include Persistence # handles how to save, create and update the model
95
- include Attributes # handles how to save and retrieve attributes
96
- include Mapping::Property # allows some additional options on the #property class method
97
- include Serialization # enable to_xml and to_json
98
- include Timestamps # handle created_at, updated_at timestamp properties
99
- include Validations # enable validations
100
- include Callbacks # enable callbacks
101
- include Finders # ActiveRecord style find
102
- include Relationships # for none persisted relationships
104
+ extend ActiveModel::Translation
105
+
106
+ include Persistence # handles how to save, create and update the model
107
+ include Attributes # handles how to save and retrieve attributes
108
+ include Mapping::Property # allows some additional options on the #property class method
109
+ include Serialization # enable to_xml and to_json
110
+ include Timestamps # handle created_at, updated_at timestamp properties
111
+ include Validations # enable validations
112
+ include Callbacks # enable callbacks
113
+ include Finders # ActiveRecord style find
114
+ include Relationships # for none persisted relationships
103
115
  end
104
116
  end
105
117
  end
@@ -102,7 +102,7 @@ module Neo4j
102
102
 
103
103
  # define class methods
104
104
  singleton.send(:define_method, rule_name) do
105
- rule_node = RuleEventListener.rule_node_for(self)
105
+ rule_node = Rule.rule_node_for(self)
106
106
  rule_node.traversal(rule_name)
107
107
  end unless respond_to?(rule_name)
108
108
 
@@ -111,11 +111,11 @@ module Neo4j
111
111
  instance_eval &block
112
112
  end
113
113
 
114
- rule = RuleEventListener.add(self, rule_name, props, &block)
114
+ rule = Rule.add(self, rule_name, props, &block)
115
115
 
116
116
  rule.functions && rule.functions.each do |func|
117
117
  singleton.send(:define_method, func.class.function_name) do |r_name, *args|
118
- rule_node = RuleEventListener.rule_node_for(self)
118
+ rule_node = Rule.rule_node_for(self)
119
119
  function_id = args.empty? ? "_classname" : args[0]
120
120
  function = rule_node.find_function(r_name, func.class.function_name, function_id)
121
121
  function.value(rule_node.rule_node, r_name)
@@ -124,7 +124,7 @@ module Neo4j
124
124
  end
125
125
 
126
126
  def inherit_rules_from(clazz)
127
- RuleEventListener.inherit(clazz, self)
127
+ Rule.inherit(clazz, self)
128
128
  end
129
129
 
130
130
  # This is typically used for RSpecs to clean up rule nodes created by the #rule method.
@@ -133,7 +133,7 @@ module Neo4j
133
133
  singelton = class << self;
134
134
  self;
135
135
  end
136
- rule_node = RuleEventListener.rule_node_for(self)
136
+ rule_node = Rule.rule_node_for(self)
137
137
 
138
138
  rule_node.rule_names.each {|rule_name| singelton.send(:remove_method, rule_name)}
139
139
  rule_node.rules.clear
@@ -145,7 +145,7 @@ module Neo4j
145
145
  # Can also be called from an migration.
146
146
  #
147
147
  def trigger_rules(node, *changes)
148
- RuleEventListener.trigger_rules(node, *changes)
148
+ Rule.trigger_rules(node, *changes)
149
149
  end
150
150
 
151
151
  # Returns a proc that will call add method on the given function
@@ -167,7 +167,7 @@ module Neo4j
167
167
  # Returns a proc that calls the given method on the given function.
168
168
  def function_for(method, rule_name, function_name_or_class, function_id = '_classname')
169
169
  function_name = function_name_or_class.is_a?(Symbol)? function_name_or_class : function_name_or_class.function_name
170
- rule_node = RuleEventListener.rule_node_for(self)
170
+ rule_node = Rule.rule_node_for(self)
171
171
  rule = rule_node.find_rule(rule_name)
172
172
  rule_node_raw = rule_node.rule_node
173
173
 
@@ -179,6 +179,5 @@ module Neo4j
179
179
  end
180
180
  end
181
181
 
182
- Neo4j.unstarted_db.event_handler.add(RuleEventListener) unless Neo4j.read_only?
183
182
  end
184
183
  end
@@ -0,0 +1,60 @@
1
+ module Neo4j
2
+ module Rule
3
+ class EventListener
4
+ class << self
5
+ # ----------------------------------------------------------------------------------------------------------------
6
+ # Event handling methods
7
+ # ----------------------------------------------------------------------------------------------------------------
8
+
9
+ def on_relationship_created(rel, *)
10
+ trigger_start_node = Rule.trigger?(rel._start_node)
11
+ trigger_end_node = Rule.trigger?(rel._end_node)
12
+ Rule.trigger_rules(rel._start_node) if trigger_start_node
13
+ Rule.trigger_rules(rel._end_node) if trigger_end_node
14
+ end
15
+
16
+ def on_property_changed(node, *changes)
17
+ Rule.trigger_rules(node, *changes) if Rule.trigger?(node)
18
+ end
19
+
20
+ def on_node_deleted(node, old_properties, data)
21
+ # have we deleted a rule node ?
22
+ del_rule_node = Rule.find_rule_node(node)
23
+ del_rule_node && del_rule_node.clear_rule_node
24
+ return if del_rule_node
25
+
26
+ # do we have prop_aggregations for this
27
+ clazz = old_properties['_classname']
28
+ rule_node = Rule.rule_node_for(clazz)
29
+ return if rule_node.nil?
30
+
31
+ id = node.getId
32
+ rule_node.rules.each do |rule|
33
+ next if rule.functions.nil?
34
+ rule_name = rule.rule_name.to_s
35
+
36
+ # is the rule node deleted ?
37
+ deleted_rule_node = data.deletedNodes.find { |n| n == rule_node.rule_node }
38
+ next if deleted_rule_node
39
+
40
+ rule.functions.each do |function|
41
+ next unless data.deletedRelationships.find do |r|
42
+ r.getEndNode().getId() == id && r.rel_type == rule_name
43
+ end
44
+ previous_value = old_properties[function.function_id]
45
+ function.delete(rule_name, rule_node.rule_node, previous_value) if previous_value
46
+ end if rule.functions
47
+ end
48
+ end
49
+
50
+ def on_neo4j_started(*)
51
+ Rule.on_neo4j_started
52
+ end
53
+ end
54
+
55
+
56
+ end
57
+ Neo4j.unstarted_db.event_handler.add(EventListener) unless Neo4j.read_only?
58
+
59
+ end
60
+ end
@@ -1,5 +1,130 @@
1
- require 'neo4j/rule/rule_event_listener'
1
+ require 'neo4j/rule/event_listener'
2
2
  require 'neo4j/rule/class_methods'
3
3
  require 'neo4j/rule/rule_node'
4
4
 
5
- require 'neo4j/rule/functions/functions'
5
+ require 'neo4j/rule/functions/functions'
6
+
7
+
8
+ module Neo4j
9
+ module Rule
10
+
11
+
12
+ # Holds all defined rules added by the Neo4j::Rule::ClassMethods#rule method.
13
+ #
14
+ # See Neo4j::Rule::ClassMethods
15
+ #
16
+ class Rule
17
+
18
+ attr_reader :rule_name, :filter, :triggers, :functions
19
+
20
+ def initialize(rule_name, props, &block)
21
+ @rule_name = rule_name
22
+ @triggers = props[:triggers]
23
+ @functions = props[:functions]
24
+ @triggers = [@triggers] if @triggers && !@triggers.respond_to?(:each)
25
+ @functions = [@functions] if @functions && !@functions.respond_to?(:each)
26
+ @filter = block
27
+ end
28
+
29
+ def to_s
30
+ "Rule #{rule_name} props=#{props.inspect}"
31
+ end
32
+
33
+ def find_function(function_name, function_id)
34
+ function_id = function_id.to_s
35
+ @functions && @functions.find { |f| f.function_id == function_id && f.class.function_name == function_name }
36
+ end
37
+
38
+ # Reconstruct the properties given when created this rule
39
+ # Needed when inheriting a rule and we want to duplicate a rule
40
+ def props
41
+ props = {}
42
+ props[:triggers] = @triggers if @triggers
43
+ props[:functions] = @functions if @functions
44
+ props
45
+ end
46
+
47
+ def functions_for(property)
48
+ @functions && @functions.find_all { |f| f.calculate?(property) }
49
+ end
50
+
51
+ def execute_filter(node)
52
+ if @filter.nil?
53
+ true
54
+ elsif @filter.arity != 1
55
+ node.wrapper.instance_eval(&@filter)
56
+ else
57
+ @filter.call(node)
58
+ end
59
+ end
60
+
61
+ # ------------------------------------------------------------------------------------------------------------------
62
+ # Class Methods
63
+ # ------------------------------------------------------------------------------------------------------------------
64
+
65
+ class << self
66
+ def add(clazz, rule_name, props, &block)
67
+ rule_node = rule_node_for(clazz.to_s)
68
+ rule_node.remove_rule(rule_name) # remove any previously inherited rules
69
+ rule = Rule.new(rule_name, props, &block)
70
+ rule_node.add_rule(rule)
71
+ rule
72
+ end
73
+
74
+ def has_rules?(clazz)
75
+ !@rule_nodes[clazz.to_s].nil?
76
+ end
77
+
78
+ def rule_names_for(clazz)
79
+ rule_node = rule_node_for(clazz)
80
+ rule_node.rules.map { |rule| rule.rule_name }
81
+ end
82
+
83
+ def rule_node_for(clazz)
84
+ return nil if clazz.nil?
85
+ @rule_nodes ||= {}
86
+ @rule_nodes[clazz.to_s] ||= RuleNode.new(clazz)
87
+ end
88
+
89
+ def find_rule_node(node)
90
+ @rule_nodes && @rule_nodes.values.find { |rn| rn.rule_node?(node) }
91
+ end
92
+
93
+ def on_neo4j_started
94
+ @rule_nodes.each_value { |rule_node| rule_node.on_neo4j_started } if @rule_nodes
95
+ end
96
+
97
+ def inherit(parent_class, subclass)
98
+ # copy all the rules
99
+ if rule_node = rule_node_for(parent_class)
100
+ rule_node.inherit(subclass)
101
+ end
102
+ end
103
+
104
+ def delete(clazz)
105
+ if rule_node = rule_node_for(clazz)
106
+ rule_node.delete_node
107
+ end
108
+ end
109
+
110
+ def trigger?(node)
111
+ classname = node[:_classname]
112
+ @rule_nodes && classname && rule_node_for(classname)
113
+ end
114
+
115
+ def trigger_rules(node, *changes)
116
+ classname = node[:_classname]
117
+ return unless classname # there are no rules if there is not a :_classname property
118
+ rule_node = rule_node_for(classname)
119
+ rule_node.execute_rules(node, *changes)
120
+
121
+ # recursively add relationships for all the parent classes with rules that also pass for this node
122
+ if (clazz = eval("#{classname}.superclass")) && clazz.include?(Neo4j::NodeMixin)
123
+ rule_node = rule_node_for(clazz)
124
+ rule_node && rule_node.execute_rules(node, *changes)
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -65,7 +65,7 @@ module Neo4j
65
65
 
66
66
  def to_ruby(value)
67
67
  return nil if value.nil?
68
- Time.at(value).utc
68
+ Time.at(value).utc.to_date
69
69
  end
70
70
  end
71
71
  end
data/lib/neo4j/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Neo4j
2
- VERSION = "1.0.0.beta.28"
2
+ VERSION = "1.0.0.beta.29"
3
3
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: neo4j
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: 6
5
- version: 1.0.0.beta.28
5
+ version: 1.0.0.beta.29
6
6
  platform: java
7
7
  authors:
8
8
  - Andreas Ronge
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-02-02 00:00:00 +01:00
13
+ date: 2011-02-10 00:00:00 +01:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -154,6 +154,8 @@ files:
154
154
  - lib/neo4j/index/index.rb
155
155
  - lib/neo4j/batch/inserter.rb
156
156
  - lib/neo4j/batch/indexer.rb
157
+ - lib/neo4j/batch/rule_inserter.rb
158
+ - lib/neo4j/batch/rule_node.rb
157
159
  - lib/neo4j/batch/batch.rb
158
160
  - lib/neo4j/has_n/decl_relationship_dsl.rb
159
161
  - lib/neo4j/has_n/has_n.rb
@@ -164,7 +166,7 @@ files:
164
166
  - lib/neo4j/rule/rule.rb
165
167
  - lib/neo4j/rule/rule_node.rb
166
168
  - lib/neo4j/rule/class_methods.rb
167
- - lib/neo4j/rule/rule_event_listener.rb
169
+ - lib/neo4j/rule/event_listener.rb
168
170
  - lib/neo4j/rule/functions/function.rb
169
171
  - lib/neo4j/rule/functions/count.rb
170
172
  - lib/neo4j/rule/functions/sum.rb
@@ -1,162 +0,0 @@
1
- module Neo4j
2
- module Rule
3
-
4
-
5
- # Holds all defined rules and trigger them when an event is received.
6
- #
7
- # See Neo4j::Rule::ClassMethods
8
- #
9
- class RuleEventListener #:nodoc:
10
-
11
- attr_reader :rule_name, :filter, :triggers, :functions
12
-
13
- def initialize(rule_name, props, &block)
14
- @rule_name = rule_name
15
- @triggers = props[:triggers]
16
- @functions = props[:functions]
17
- @triggers = [@triggers] if @triggers && !@triggers.respond_to?(:each)
18
- @functions = [@functions] if @functions && !@functions.respond_to?(:each)
19
- @filter = block
20
- end
21
-
22
- def to_s
23
- "RuleEventListener #{rule_name} props=#{props.inspect}"
24
- end
25
-
26
- def find_function(function_name, function_id)
27
- function_id = function_id.to_s
28
- @functions && @functions.find { |f| f.function_id == function_id && f.class.function_name == function_name }
29
- end
30
-
31
- # Reconstruct the properties given when created this rule
32
- # Needed when inheriting a rule and we want to duplicate a rule
33
- def props
34
- props = {}
35
- props[:triggers] = @triggers if @triggers
36
- props[:functions] = @functions if @functions
37
- props
38
- end
39
-
40
- def functions_for(property)
41
- @functions && @functions.find_all { |f| f.calculate?(property) }
42
- end
43
-
44
- def execute_filter(node)
45
- if @filter.nil?
46
- true
47
- elsif @filter.arity != 1
48
- node.wrapper.instance_eval(&@filter)
49
- else
50
- @filter.call(node)
51
- end
52
- end
53
-
54
- # ------------------------------------------------------------------------------------------------------------------
55
- # Class Methods
56
- # ------------------------------------------------------------------------------------------------------------------
57
-
58
- class << self
59
- def add(clazz, rule_name, props, &block)
60
- rule_node = rule_node_for(clazz.to_s)
61
- rule_node.remove_rule(rule_name) # remove any previously inherited rules
62
- rule = RuleEventListener.new(rule_name, props, &block)
63
- rule_node.add_rule(rule)
64
- rule
65
- end
66
-
67
- def rule_names_for(clazz)
68
- rule_node = rule_node_for(clazz)
69
- rule_node.rules.map { |rule| rule.rule_name }
70
- end
71
-
72
- def rule_node_for(clazz)
73
- return nil if clazz.nil?
74
- @rule_nodes ||= {}
75
- @rule_nodes[clazz.to_s] ||= RuleNode.new(clazz)
76
- end
77
-
78
- def inherit(parent_class, subclass)
79
- # copy all the rules
80
- if rule_node = rule_node_for(parent_class)
81
- rule_node.inherit(subclass)
82
- end
83
- end
84
-
85
- def delete(clazz)
86
- if rule_node = rule_node_for(clazz)
87
- rule_node.delete_node
88
- end
89
- end
90
-
91
- def trigger?(node)
92
- classname = node[:_classname]
93
- @rule_nodes && classname && rule_node_for(classname)
94
- end
95
-
96
- def trigger_rules(node, *changes)
97
- classname = node[:_classname]
98
- return unless classname # there are no rules if there is not a :_classname property
99
- rule_node = rule_node_for(classname)
100
- rule_node.execute_rules(node, *changes)
101
-
102
- # recursively add relationships for all the parent classes with rules that also pass for this node
103
- if (clazz = eval("#{classname}.superclass")) && clazz.include?(Neo4j::NodeMixin)
104
- rule_node = rule_node_for(clazz)
105
- rule_node && rule_node.execute_rules(node, *changes)
106
- end
107
- end
108
-
109
-
110
- # ----------------------------------------------------------------------------------------------------------------
111
- # Event handling methods
112
- # ----------------------------------------------------------------------------------------------------------------
113
-
114
- def on_relationship_created(rel, *)
115
- trigger_start_node = trigger?(rel._start_node)
116
- trigger_end_node = trigger?(rel._end_node)
117
- trigger_rules(rel._start_node) if trigger_start_node
118
- trigger_rules(rel._end_node) if trigger_end_node
119
- end
120
-
121
- def on_property_changed(node, *changes)
122
- trigger_rules(node, *changes) if trigger?(node)
123
- end
124
-
125
- def on_node_deleted(node, old_properties, data)
126
- # have we deleted a rule node ?
127
- del_rule_node = @rule_nodes && @rule_nodes.values.find { |rn| rn.rule_node?(node) }
128
- del_rule_node && del_rule_node.clear_rule_node
129
- return if del_rule_node
130
-
131
- # do we have prop_aggregations for this
132
- clazz = old_properties['_classname']
133
- rule_node = rule_node_for(clazz)
134
- return if rule_node.nil?
135
-
136
- id = node.getId
137
- rule_node.rules.each do |rule|
138
- next if rule.functions.nil?
139
- rule_name = rule.rule_name.to_s
140
-
141
- # is the rule node deleted ?
142
- deleted_rule_node = data.deletedNodes.find { |n| n == rule_node.rule_node }
143
- next if deleted_rule_node
144
-
145
- rule.functions.each do |function|
146
- next unless data.deletedRelationships.find do |r|
147
- r.getEndNode().getId() == id && r.rel_type == rule_name
148
- end
149
- previous_value = old_properties[function.function_id]
150
- function.delete(rule_name, rule_node.rule_node, previous_value) if previous_value
151
- end if rule.functions
152
- end
153
- end
154
-
155
- def on_neo4j_started(*)
156
- @rule_nodes.each_value { |rule_node| rule_node.on_neo4j_started } if @rule_nodes
157
- end
158
-
159
- end
160
- end
161
- end
162
- end