neo4j 1.0.0.beta.23-java → 1.0.0.beta.24-java
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/neo4j.rb +7 -0
- data/lib/neo4j/config.rb +2 -9
- data/lib/neo4j/event_handler.rb +51 -1
- data/lib/neo4j/functions/count.rb +33 -0
- data/lib/neo4j/functions/function.rb +72 -0
- data/lib/neo4j/functions/sum.rb +27 -0
- data/lib/neo4j/mapping/class_methods/property.rb +2 -1
- data/lib/neo4j/mapping/class_methods/rule.rb +30 -173
- data/lib/neo4j/mapping/node_mixin.rb +3 -1
- data/lib/neo4j/mapping/rule.rb +155 -0
- data/lib/neo4j/mapping/rule_node.rb +177 -0
- data/lib/neo4j/neo4j.rb +0 -4
- data/lib/neo4j/node.rb +12 -2
- data/lib/neo4j/node_relationship.rb +1 -1
- data/lib/neo4j/node_traverser.rb +11 -1
- data/lib/neo4j/rails/finders.rb +1 -1
- data/lib/neo4j/rails/persistence.rb +1 -0
- data/lib/neo4j/rails/relationships/relationships.rb +8 -5
- data/lib/neo4j/relationship.rb +12 -1
- data/lib/neo4j/type_converters.rb +121 -62
- data/lib/neo4j/version.rb +1 -1
- data/lib/tmp/neo4j/index/lucene-store.db +0 -0
- data/lib/tmp/neo4j/lucene-fulltext/lucene-store.db +0 -0
- data/lib/tmp/neo4j/lucene/lucene-store.db +0 -0
- data/lib/tmp/neo4j/messages.log +43 -176
- data/lib/tmp/neo4j/neostore +0 -0
- data/lib/tmp/neo4j/neostore.nodestore.db +0 -0
- data/lib/tmp/neo4j/neostore.nodestore.db.id +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.id +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.index.keys +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.index.keys.id +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.strings +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.strings.id +0 -0
- data/lib/tmp/neo4j/neostore.relationshipstore.db +0 -0
- data/lib/tmp/neo4j/neostore.relationshipstore.db.id +0 -0
- data/lib/tmp/neo4j/neostore.relationshiptypestore.db +0 -0
- data/lib/tmp/neo4j/neostore.relationshiptypestore.db.id +0 -0
- data/lib/tmp/neo4j/neostore.relationshiptypestore.db.names +0 -0
- data/lib/tmp/neo4j/neostore.relationshiptypestore.db.names.id +0 -0
- data/lib/tmp/neo4j/tm_tx_log.1 +0 -0
- metadata +8 -11
- data/lib/tmp/neo4j/index.db +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Person-exact/_0.cfs +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Person-exact/_1.cfs +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Person-exact/segments.gen +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Person-exact/segments_3 +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Thing-exact/_0.cfs +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Thing-exact/segments.gen +0 -0
- data/lib/tmp/neo4j/index/lucene/node/Thing-exact/segments_2 +0 -0
data/lib/neo4j.rb
CHANGED
@@ -23,6 +23,11 @@ require 'neo4j/config'
|
|
23
23
|
require 'neo4j/database'
|
24
24
|
require 'neo4j/neo4j'
|
25
25
|
|
26
|
+
require "neo4j/functions/function"
|
27
|
+
require "neo4j/functions/count"
|
28
|
+
require "neo4j/functions/sum"
|
29
|
+
|
30
|
+
|
26
31
|
require 'neo4j/index/index'
|
27
32
|
require 'neo4j/index/class_methods'
|
28
33
|
require 'neo4j/index/indexer_registry'
|
@@ -46,6 +51,8 @@ require 'neo4j/mapping/has_n'
|
|
46
51
|
require 'neo4j/mapping/has_list'
|
47
52
|
require 'neo4j/mapping/node_mixin'
|
48
53
|
require 'neo4j/mapping/relationship_mixin'
|
54
|
+
require 'neo4j/mapping/rule'
|
55
|
+
require 'neo4j/mapping/rule_node'
|
49
56
|
require 'neo4j/node_mixin'
|
50
57
|
require 'neo4j/relationship_mixin'
|
51
58
|
require 'neo4j/mapping/class_methods/rule'
|
data/lib/neo4j/config.rb
CHANGED
@@ -13,7 +13,6 @@ module Neo4j
|
|
13
13
|
# <tt>:storage_path</tt>:: default <tt>tmp/neo4j</tt> where the database is stored
|
14
14
|
# <tt>:timestamps</tt>:: default <tt>true</tt> for Rails Neo4j::Model - if timestamps should be used when saving the model
|
15
15
|
# <tt>:lucene</tt>:: default hash keys: <tt>:fulltext</tt>, <tt>:exact</tt> configuration how the lucene index is stored
|
16
|
-
# <tt>:converters</tt>:: defines which converters should be used before writing and reading to neo4j, see Neo4j::TypeConverters
|
17
16
|
#
|
18
17
|
class Config
|
19
18
|
# This code is copied from merb-core/config.rb.
|
@@ -27,12 +26,6 @@ module Neo4j
|
|
27
26
|
:storage_path => 'tmp/neo4j',
|
28
27
|
:timestamps => true,
|
29
28
|
|
30
|
-
# TODO: Just pickup all converter classes that are in the Neo4j::TypeConverters module?
|
31
|
-
:converters => { Date => Neo4j::TypeConverters::DateConverter,
|
32
|
-
DateTime => Neo4j::TypeConverters::DateTimeConverter,
|
33
|
-
Time => Neo4j::TypeConverters::TimeConverter
|
34
|
-
},
|
35
|
-
|
36
29
|
:lucene => {
|
37
30
|
:fulltext => {"provider" => "lucene", "type" => "fulltext" },
|
38
31
|
:exact => {"provider" => "lucene", "type" => "exact" }}
|
@@ -117,10 +110,10 @@ module Neo4j
|
|
117
110
|
@configuration.fetch(key, default)
|
118
111
|
end
|
119
112
|
|
120
|
-
# Sets up the configuration
|
113
|
+
# Sets up the configuration to use the default.
|
121
114
|
#
|
122
115
|
# ==== Returns
|
123
|
-
# The configuration as a hash.
|
116
|
+
# The a new configuration using default values as a hash.
|
124
117
|
#
|
125
118
|
def setup()
|
126
119
|
@configuration = {}
|
data/lib/neo4j/event_handler.rb
CHANGED
@@ -13,7 +13,57 @@ module Neo4j
|
|
13
13
|
# * <tt>on_property_changed</tt>
|
14
14
|
# * <tt>on_rel_property_changed</tt>
|
15
15
|
#
|
16
|
-
#
|
16
|
+
# ==== on_neo4j_started(db)
|
17
|
+
#
|
18
|
+
# Called when the neo4j engine starts.
|
19
|
+
# Notice that the neo4j will be started automatically when the first neo4j operation is performed.
|
20
|
+
# You can also start Neo4j: <tt>Neo4j.start</tt>
|
21
|
+
#
|
22
|
+
# * <tt>db</tt> :: the Neo4j::Database instance
|
23
|
+
#
|
24
|
+
# ==== on_neo4j_shutdown(db)
|
25
|
+
#
|
26
|
+
# Called when the neo4j engine shutdown. You don't need to call <tt>Neo4j.shutdown</tt> since
|
27
|
+
# the it will automatically be shutdown when the application exits (using the at_exit ruby hook).
|
28
|
+
#
|
29
|
+
# * <tt>db</tt> :: the Neo4j::Database instance
|
30
|
+
#
|
31
|
+
# ==== on_node_created(node)
|
32
|
+
#
|
33
|
+
# * <tt>node</tt> :: the node that was created
|
34
|
+
#
|
35
|
+
# ==== on_node_deleted(node, old_props, tx_data)
|
36
|
+
#
|
37
|
+
# * <tt>node</tt> :: the node that was deleted
|
38
|
+
# * <tt>old_props</tt> :: a hash of the old properties this node had
|
39
|
+
# * <tt>tx_data</tt> :: the Java Transaction Data object, http://api.neo4j.org/current/org/neo4j/graphdb/event/TransactionData.html
|
40
|
+
#
|
41
|
+
# ==== on_relationship_created(rel, tx_data)
|
42
|
+
#
|
43
|
+
# * <tt>rel</tt> :: the relationship that was created
|
44
|
+
# * <tt>tx_data</tt> :: the Java Transaction Data object, http://api.neo4j.org/current/org/neo4j/graphdb/event/TransactionData.html
|
45
|
+
#
|
46
|
+
# ==== on_relationship_deleted(rel, old_props, tx_data)
|
47
|
+
#
|
48
|
+
# * <tt>rel</tt> :: the relationship that was created
|
49
|
+
# * <tt>old_props</tt> :: a hash of the old properties this relationship had
|
50
|
+
# * <tt>tx_data</tt> :: the Java Transaction Data object, http://api.neo4j.org/current/org/neo4j/graphdb/event/TransactionData.html
|
51
|
+
#
|
52
|
+
# ==== on_property_changed(node, key, old_value, new_value)
|
53
|
+
#
|
54
|
+
# * <tt>node</tt> :: the node
|
55
|
+
# * <tt>key</tt> :: the name of the property that was changed (String)
|
56
|
+
# * <tt>old_value</tt> :: old value of the property
|
57
|
+
# * <tt>new_value</tt> :: new value of the property
|
58
|
+
#
|
59
|
+
# ==== on_rel_property_changed(rel, key, old_value, new_value)
|
60
|
+
#
|
61
|
+
# * <tt>rel</tt> :: the node that was created
|
62
|
+
# * <tt>key</tt> :: the name of the property that was changed (String)
|
63
|
+
# * <tt>old_value</tt> :: old value of the property
|
64
|
+
# * <tt>new_value</tt> :: new value of the property
|
65
|
+
#
|
66
|
+
# == Usage
|
17
67
|
#
|
18
68
|
# class MyListener
|
19
69
|
# def on_node_deleted(node, old_props, tx_data)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Functions
|
3
|
+
class Count < Function
|
4
|
+
def initialize
|
5
|
+
@property = '_classname'
|
6
|
+
end
|
7
|
+
|
8
|
+
def calculate?(changed_property)
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def delete(rule_name, rule_node, old_value)
|
13
|
+
key = rule_node_property(rule_name)
|
14
|
+
rule_node[key] ||= 0
|
15
|
+
rule_node[key] -= 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(rule_name, rule_node, new_value)
|
19
|
+
key = rule_node_property(rule_name)
|
20
|
+
rule_node[key] ||= 0
|
21
|
+
rule_node[key] += 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def update(*)
|
25
|
+
# we are only counting, not interested in property changes
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.function_name
|
29
|
+
:count
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Functions
|
3
|
+
|
4
|
+
# The base class of rule functions.
|
5
|
+
#
|
6
|
+
# You are expected to at least implement two methods:
|
7
|
+
# * update :: update the rule node value of this function
|
8
|
+
# * function_name :: the name of this function, the name of the generated method - A class method !
|
9
|
+
#
|
10
|
+
class Function
|
11
|
+
|
12
|
+
# Initialize the the function with a property which is usually the same as the function identity.
|
13
|
+
# See the #calculate? method how this property is used.
|
14
|
+
#
|
15
|
+
def initialize(property)
|
16
|
+
@property = property.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"Function #{self.class.function_name} function_id: #{function_id}"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Decides if the function should be called are not
|
24
|
+
#
|
25
|
+
def calculate?(changed_property)
|
26
|
+
@property == changed_property
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
# The identity of the function.
|
31
|
+
# Used to identify function.
|
32
|
+
#
|
33
|
+
# ==== Example
|
34
|
+
# Person.sum(:young, :age)
|
35
|
+
#
|
36
|
+
# In the example above the property :age is the used to identify which function will be called
|
37
|
+
# since there could be several sum method. In the example we want use the sum method that uses the :age property.
|
38
|
+
#
|
39
|
+
def function_id
|
40
|
+
@property
|
41
|
+
end
|
42
|
+
|
43
|
+
# The value of the rule
|
44
|
+
def value(rule_node, rule_name)
|
45
|
+
key = rule_node_property(rule_name)
|
46
|
+
rule_node[key] || 0
|
47
|
+
end
|
48
|
+
|
49
|
+
# Called when a node is removed from a rule group
|
50
|
+
# Default is calling update method which is expected to be implemented in a subclass
|
51
|
+
def delete(rule_name, rule_node, old_value)
|
52
|
+
update(rule_name, rule_node, old_value, nil)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Called when a node is added to a rule group
|
56
|
+
# Default is calling update method which is expected to be implemented in a subclass
|
57
|
+
def add(rule_name, rule_node, new_value)
|
58
|
+
update(rule_name, rule_node, nil, new_value)
|
59
|
+
end
|
60
|
+
|
61
|
+
# the name of the property that holds the value of the function
|
62
|
+
def rule_node_property(rule_name)
|
63
|
+
self.class.rule_node_property(self.class.function_name, rule_name, @property)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.rule_node_property(function_name, rule_name, prop)
|
67
|
+
"_#{function_name}_#{rule_name}_#{prop}"
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Functions
|
3
|
+
|
4
|
+
class Sum < Function
|
5
|
+
# Updates the function's value.
|
6
|
+
# Called after the transactions commits and a property has been changed on a node.
|
7
|
+
#
|
8
|
+
# ==== Arguments
|
9
|
+
# * rule_name :: the name of the rule group
|
10
|
+
# * rule_node :: the node which contains the value of this function
|
11
|
+
# * old_value new value :: the changed value of the property (when the transaction commits)
|
12
|
+
def update(rule_name, rule_node, old_value, new_value)
|
13
|
+
key = rule_node_property(rule_name)
|
14
|
+
rule_node[key] ||= 0
|
15
|
+
old_value ||= 0
|
16
|
+
new_value ||= 0
|
17
|
+
rule_node[key] += new_value - old_value
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.function_name
|
21
|
+
:sum
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -35,7 +35,8 @@ module Neo4j::Mapping
|
|
35
35
|
# property :since, :type => DateTime # will be converted into a fixnum
|
36
36
|
# end
|
37
37
|
#
|
38
|
-
# You can write your own converter
|
38
|
+
# You can write your own converter by writing a class that respond to :convert?, :to_ruby and
|
39
|
+
# :to_java in the Neo4j::TypeConverters module.
|
39
40
|
#
|
40
41
|
def property(*props)
|
41
42
|
if props.size == 2 and props[1].kind_of?(Hash)
|
@@ -1,154 +1,5 @@
|
|
1
1
|
module Neo4j::Mapping
|
2
2
|
module ClassMethods
|
3
|
-
# Holds all defined rules and trigger them when an event is received.
|
4
|
-
#
|
5
|
-
# See Rule
|
6
|
-
#
|
7
|
-
class Rules
|
8
|
-
class << self
|
9
|
-
def add(clazz, field, props, &block)
|
10
|
-
clazz = clazz.to_s
|
11
|
-
@rules ||= {}
|
12
|
-
# was there no ruls for this class AND is neo4j running ?
|
13
|
-
if !@rules.include?(clazz) && Neo4j.running?
|
14
|
-
# maybe Neo4j was started first and the rules was added later. Create rule nodes now
|
15
|
-
create_rule_node_for(clazz)
|
16
|
-
end
|
17
|
-
@rules[clazz] ||= {}
|
18
|
-
filter = block.nil? ? Proc.new { |*| true } : block
|
19
|
-
@rules[clazz][field] = filter
|
20
|
-
@triggers ||= {}
|
21
|
-
@triggers[clazz] ||= {}
|
22
|
-
trigger = props[:trigger].nil? ? [] : props[:trigger]
|
23
|
-
@triggers[clazz][field] = trigger.respond_to?(:each) ? trigger : [trigger]
|
24
|
-
end
|
25
|
-
|
26
|
-
def inherit(parent_class, subclass)
|
27
|
-
# copy all the rules
|
28
|
-
@rules[parent_class.to_s].each_pair do |field, filter|
|
29
|
-
subclass.rule field, &filter
|
30
|
-
end if @rules[parent_class.to_s]
|
31
|
-
end
|
32
|
-
|
33
|
-
def trigger_other_rules(node)
|
34
|
-
clazz = node[:_classname]
|
35
|
-
@rules[clazz].keys.each do |field|
|
36
|
-
rel_types = @triggers[clazz][field]
|
37
|
-
rel_types.each do |rel_type|
|
38
|
-
node.incoming(rel_type).each { |n| n.trigger_rules }
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def fields_for(clazz)
|
44
|
-
clazz = clazz.to_s
|
45
|
-
return [] if @rules.nil? || @rules[clazz].nil?
|
46
|
-
@rules[clazz].keys
|
47
|
-
end
|
48
|
-
|
49
|
-
def delete(clazz)
|
50
|
-
clazz = clazz.to_s
|
51
|
-
# delete the rule node if found
|
52
|
-
if Neo4j.ref_node.rel?(clazz)
|
53
|
-
Neo4j.ref_node.outgoing(clazz).each { |n| n.del }
|
54
|
-
end
|
55
|
-
@rules.delete(clazz) if @rules
|
56
|
-
end
|
57
|
-
|
58
|
-
def on_neo4j_started(*)
|
59
|
-
@rules.each_key { |clazz| create_rule_node_for(clazz) } if @rules
|
60
|
-
end
|
61
|
-
|
62
|
-
def create_rule_node_for(clazz)
|
63
|
-
if !Neo4j.ref_node.rel?(clazz)
|
64
|
-
Neo4j::Transaction.run do
|
65
|
-
node = Neo4j::Node.new
|
66
|
-
Neo4j.ref_node.outgoing(clazz) << node
|
67
|
-
node
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def trigger?(node)
|
73
|
-
@rules && node.property?(:_classname) && @rules.include?(node[:_classname])
|
74
|
-
end
|
75
|
-
|
76
|
-
def rule_for(clazz)
|
77
|
-
if Neo4j.ref_node.rel?(clazz)
|
78
|
-
Neo4j.ref_node._rel(:outgoing, clazz)._end_node
|
79
|
-
else
|
80
|
-
# this should be called if the rule node gets deleted
|
81
|
-
create_rule_node_for(clazz)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
def on_relationship_created(rel, *)
|
87
|
-
trigger_start_node = trigger?(rel._start_node)
|
88
|
-
trigger_end_node = trigger?(rel._end_node)
|
89
|
-
# end or start node must be triggered by this event
|
90
|
-
return unless trigger_start_node || trigger_end_node
|
91
|
-
on_property_changed(trigger_start_node ? rel._start_node : rel._end_node)
|
92
|
-
end
|
93
|
-
|
94
|
-
|
95
|
-
def on_property_changed(node, *)
|
96
|
-
trigger_rules(node) if trigger?(node)
|
97
|
-
end
|
98
|
-
|
99
|
-
def trigger_rules(node)
|
100
|
-
trigger_rules_for_class(node, node[:_classname])
|
101
|
-
trigger_other_rules(node)
|
102
|
-
end
|
103
|
-
|
104
|
-
def trigger_rules_for_class(node, clazz)
|
105
|
-
return if @rules[clazz].nil?
|
106
|
-
|
107
|
-
agg_node = rule_for(clazz)
|
108
|
-
@rules[clazz].each_pair do |field, rule|
|
109
|
-
if run_rule(rule, node)
|
110
|
-
# is this node already included ?
|
111
|
-
unless connected?(field, agg_node, node)
|
112
|
-
agg_node.outgoing(field) << node
|
113
|
-
end
|
114
|
-
else
|
115
|
-
# remove old ?
|
116
|
-
break_connection(field, agg_node, node)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
# recursively add relationships for all the parent classes with rules that also pass for this node
|
121
|
-
if clazz = eval("#{clazz}.superclass")
|
122
|
-
trigger_rules_for_class(node, clazz.to_s)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
# work out if two nodes are connected by a particular relationship
|
127
|
-
# uses the end_node to start with because it's more likely to have less relationships to go through
|
128
|
-
# (just the number of superclasses it has really)
|
129
|
-
def connected?(relationship, start_node, end_node)
|
130
|
-
end_node.incoming(relationship).each do |n|
|
131
|
-
return true if n == start_node
|
132
|
-
end
|
133
|
-
false
|
134
|
-
end
|
135
|
-
|
136
|
-
# sever a direct one-to-one relationship if it exists
|
137
|
-
def break_connection(relationship, start_node, end_node)
|
138
|
-
end_node.rels(relationship).incoming.each do |r|
|
139
|
-
return r.del if r.start_node == start_node
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def run_rule(rule, node)
|
144
|
-
if rule.arity != 1
|
145
|
-
node.wrapper.instance_eval(&rule)
|
146
|
-
else
|
147
|
-
rule.call(node)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
3
|
|
153
4
|
|
154
5
|
# Allows you to group nodes by providing a rule.
|
@@ -196,7 +47,7 @@ module Neo4j::Mapping
|
|
196
47
|
# class Reader
|
197
48
|
# include Neo4j::NodeMixin
|
198
49
|
# property :age
|
199
|
-
# rule(:young, :
|
50
|
+
# rule(:young, :triggers => :readers) { age < 15 }
|
200
51
|
# end
|
201
52
|
#
|
202
53
|
# class NewsStory
|
@@ -218,7 +69,8 @@ module Neo4j::Mapping
|
|
218
69
|
# end
|
219
70
|
#
|
220
71
|
# === Thread Safe ?
|
221
|
-
#
|
72
|
+
# Yes, since operations are performed in an transaction. However you may get a deadlock exception:
|
73
|
+
# http://docs.neo4j.org/html/snapshot/#_deadlocks
|
222
74
|
#
|
223
75
|
module Rule
|
224
76
|
|
@@ -228,8 +80,10 @@ module Neo4j::Mapping
|
|
228
80
|
# Example of usage:
|
229
81
|
# class Person
|
230
82
|
# include Neo4j
|
83
|
+
# property :age
|
231
84
|
# rule :all
|
232
85
|
# rule :young { self[:age] < 10 }
|
86
|
+
# rule(:old, :functions => [Sum.new[:age]) { age > 20 }
|
233
87
|
# end
|
234
88
|
#
|
235
89
|
# p1 = Person.new :age => 5
|
@@ -239,35 +93,38 @@ module Neo4j::Mapping
|
|
239
93
|
# Person.all # => [p1,p2,p3]
|
240
94
|
# Person.young # => [p1,p2]
|
241
95
|
# p1.young? # => true
|
96
|
+
# p1.sum(old, :age) # the some of the old people's age
|
242
97
|
#
|
243
|
-
def rule(
|
244
|
-
|
98
|
+
def rule(rule_name, props = {}, &block)
|
99
|
+
singleton = class << self;
|
245
100
|
self;
|
246
101
|
end
|
247
102
|
|
248
103
|
# define class methods
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
Rules.fields_for(self).each do |filter_name|
|
254
|
-
traversal.filter_method(filter_name) do |path|
|
255
|
-
path.end_node.rel?(filter_name, :incoming)
|
256
|
-
end
|
257
|
-
end
|
258
|
-
traversal
|
259
|
-
end unless respond_to?(name)
|
104
|
+
singleton.send(:define_method, rule_name) do
|
105
|
+
rule_node = Neo4j::Mapping::Rule.rule_node_for(self)
|
106
|
+
rule_node.traversal(rule_name)
|
107
|
+
end unless respond_to?(rule_name)
|
260
108
|
|
261
109
|
# define instance methods
|
262
|
-
self.send(:define_method, "#{
|
110
|
+
self.send(:define_method, "#{rule_name}?") do
|
263
111
|
instance_eval &block
|
264
112
|
end
|
265
113
|
|
266
|
-
|
114
|
+
rule = Neo4j::Mapping::Rule.add(self, rule_name, props, &block)
|
115
|
+
|
116
|
+
rule.functions && rule.functions.each do |func|
|
117
|
+
singleton.send(:define_method, func.class.function_name) do |r_name, *args|
|
118
|
+
rule_node = Neo4j::Mapping::Rule.rule_node_for(self)
|
119
|
+
function_id = args.empty? ? "_classname" : args[0]
|
120
|
+
function = rule_node.find_function(r_name, func.class.function_name, function_id)
|
121
|
+
function.value(rule_node.rule_node, r_name)
|
122
|
+
end unless respond_to?(func.class.function_name)
|
123
|
+
end
|
267
124
|
end
|
268
125
|
|
269
126
|
def inherit_rules_from(clazz)
|
270
|
-
|
127
|
+
Neo4j::Mapping::Rule.inherit(clazz, self)
|
271
128
|
end
|
272
129
|
|
273
130
|
# This is typically used for RSpecs to clean up rule nodes created by the #rule method.
|
@@ -276,20 +133,20 @@ module Neo4j::Mapping
|
|
276
133
|
singelton = class << self;
|
277
134
|
self;
|
278
135
|
end
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
136
|
+
rule_node = Neo4j::Mapping::Rule.rule_node_for(self)
|
137
|
+
|
138
|
+
rule_node.rule_names.each {|rule_name| singelton.send(:remove_method, rule_name)}
|
139
|
+
rule_node.rules.clear
|
283
140
|
end
|
284
141
|
|
285
142
|
# Force to trigger the rules.
|
286
143
|
# You don't normally need that since it will be done automatically.
|
287
144
|
def trigger_rules(node)
|
288
|
-
|
145
|
+
Neo4j::Mapping::Rule.trigger_rules(node)
|
289
146
|
end
|
290
147
|
|
291
148
|
end
|
292
149
|
|
293
|
-
Neo4j.unstarted_db.event_handler.add(
|
150
|
+
Neo4j.unstarted_db.event_handler.add(Neo4j::Mapping::Rule) unless Neo4j.read_only?
|
294
151
|
end
|
295
152
|
end
|