neo4j 1.0.0.beta.23-java → 1.0.0.beta.24-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.
- 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
|