neo4j 1.0.0.beta.15 → 1.0.0.beta.16
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/neo4j/database.rb +6 -0
- data/lib/neo4j/event_handler.rb +1 -1
- data/lib/neo4j/index/index_registry.rb +3 -2
- data/lib/neo4j/index/indexer.rb +25 -7
- data/lib/neo4j/mapping/class_methods/relationship.rb +3 -3
- data/lib/neo4j/mapping/class_methods/rule.rb +65 -23
- data/lib/neo4j/mapping/decl_relationship_dsl.rb +13 -19
- data/lib/neo4j/mapping/has_n.rb +1 -1
- data/lib/neo4j/mapping/node_mixin.rb +8 -2
- data/lib/neo4j/mapping/relationship_mixin.rb +2 -2
- data/lib/neo4j/node.rb +1 -0
- data/lib/neo4j/node_relationship.rb +1 -1
- data/lib/neo4j/rails/model.rb +62 -47
- data/lib/neo4j/rails/transaction.rb +2 -1
- data/lib/neo4j/rails/validations/uniqueness.rb +8 -8
- data/lib/neo4j/rails/value.rb +5 -0
- data/lib/neo4j/relationship.rb +23 -1
- data/lib/neo4j/relationship_traverser.rb +37 -13
- data/lib/neo4j/version.rb +2 -2
- metadata +3 -3
data/lib/neo4j/database.rb
CHANGED
@@ -18,6 +18,12 @@ module Neo4j
|
|
18
18
|
|
19
19
|
def shutdown
|
20
20
|
if @running
|
21
|
+
# since we might keep a reference to indexes we must clear them so
|
22
|
+
# that we can start neo4j with a fresh new lucene indexes
|
23
|
+
Neo4j::Transaction.run do
|
24
|
+
Neo4j::Index::IndexerRegistry.clear_all_indexes
|
25
|
+
end
|
26
|
+
|
21
27
|
@graph.unregister_transaction_event_handler(@event_handler)
|
22
28
|
@event_handler.neo4j_shutdown(self)
|
23
29
|
@graph.shutdown
|
data/lib/neo4j/event_handler.rb
CHANGED
@@ -9,8 +9,9 @@ module Neo4j
|
|
9
9
|
|
10
10
|
def create_for(this_clazz, using_other_clazz, type)
|
11
11
|
@@indexers ||= {}
|
12
|
-
|
13
|
-
|
12
|
+
index = Indexer.new(this_clazz, type)
|
13
|
+
index.inherit_fields_from(@@indexers[using_other_clazz.to_s])
|
14
|
+
@@indexers[this_clazz.to_s] = index
|
14
15
|
end
|
15
16
|
|
16
17
|
def find_by_class(classname)
|
data/lib/neo4j/index/indexer.rb
CHANGED
@@ -1,18 +1,29 @@
|
|
1
1
|
module Neo4j
|
2
2
|
module Index
|
3
3
|
class Indexer #:nodoc:
|
4
|
-
attr_reader :indexer_for
|
4
|
+
attr_reader :indexer_for, :field_types, :via_relationships
|
5
5
|
|
6
6
|
def initialize(clazz, type)
|
7
7
|
# part of the unique name of the index
|
8
|
-
@indexer_for
|
8
|
+
@indexer_for = clazz
|
9
9
|
|
10
10
|
# do we want to index nodes or relationships ?
|
11
|
-
@type
|
11
|
+
@type = type
|
12
12
|
|
13
|
-
@indexes
|
14
|
-
@field_types
|
13
|
+
@indexes = {} # key = type, value = java neo4j index
|
14
|
+
@field_types = {} # key = field, value = type (e.g. :exact or :fulltext)
|
15
15
|
@via_relationships = {} # key = field, value = relationship
|
16
|
+
|
17
|
+
# to enable subclass indexing to work properly, store a list of parent indexers and
|
18
|
+
# whenever an operation is performed on this one, perform it on all
|
19
|
+
@parent_indexers = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def inherit_fields_from(parent_index)
|
23
|
+
return unless parent_index
|
24
|
+
@field_types.reverse_merge!(parent_index.field_types) if parent_index.respond_to?(:field_types)
|
25
|
+
@via_relationships.reverse_merge!(parent_index.via_relationships) if parent_index.respond_to?(:via_relationships)
|
26
|
+
@parent_indexers << parent_index
|
16
27
|
end
|
17
28
|
|
18
29
|
def to_s
|
@@ -87,12 +98,15 @@ module Neo4j
|
|
87
98
|
dsl = @via_relationships[field]
|
88
99
|
to_class = dsl.to_class
|
89
100
|
|
90
|
-
dsl.
|
101
|
+
dsl._all_relationships(node).each do |rel|
|
91
102
|
other = rel._start_node
|
92
|
-
to_class._indexer.
|
103
|
+
to_class._indexer.update_single_index_on(other, field, old_val, new_val)
|
93
104
|
end
|
94
105
|
end
|
106
|
+
update_single_index_on(node, field, old_val, new_val)
|
107
|
+
end
|
95
108
|
|
109
|
+
def update_single_index_on(node, field, old_val, new_val)
|
96
110
|
if @field_types.include?(field)
|
97
111
|
rm_index(node, field, old_val) if old_val
|
98
112
|
add_index(node, field, new_val) if new_val
|
@@ -113,11 +127,15 @@ module Neo4j
|
|
113
127
|
end
|
114
128
|
|
115
129
|
def add_index(entity, field, value)
|
130
|
+
return false unless @field_types.has_key?(field)
|
116
131
|
index_for_field(field.to_s).add(entity, field, value)
|
132
|
+
@parent_indexers.each { |i| i.add_index(entity, field, value) }
|
117
133
|
end
|
118
134
|
|
119
135
|
def rm_index(entity, field, value)
|
136
|
+
return false unless @field_types.has_key?(field)
|
120
137
|
index_for_field(field).remove(entity, field, value)
|
138
|
+
@parent_indexers.each { |i| i.rm_index(entity, field, value) }
|
121
139
|
end
|
122
140
|
|
123
141
|
def find(query, params = {})
|
@@ -33,10 +33,10 @@ module Neo4j::Mapping
|
|
33
33
|
module_eval(%Q{
|
34
34
|
def #{rel_type}_rels
|
35
35
|
dsl = #{clazz}._decl_rels[:'#{rel_type.to_s}']
|
36
|
-
dsl.all_relationships(self)
|
36
|
+
dsl.all_relationships(self)
|
37
37
|
end}, __FILE__, __LINE__)
|
38
38
|
|
39
|
-
_decl_rels[rel_type.to_sym] = Neo4j::Mapping::DeclRelationshipDsl.new(rel_type, false, params)
|
39
|
+
_decl_rels[rel_type.to_sym] = Neo4j::Mapping::DeclRelationshipDsl.new(rel_type, false, clazz, params)
|
40
40
|
end
|
41
41
|
|
42
42
|
|
@@ -80,7 +80,7 @@ module Neo4j::Mapping
|
|
80
80
|
dsl.single_relationship(self)
|
81
81
|
end}, __FILE__, __LINE__)
|
82
82
|
|
83
|
-
_decl_rels[rel_type.to_sym] = Neo4j::Mapping::DeclRelationshipDsl.new(rel_type, true, params)
|
83
|
+
_decl_rels[rel_type.to_sym] = Neo4j::Mapping::DeclRelationshipDsl.new(rel_type, true, clazz, params)
|
84
84
|
end
|
85
85
|
|
86
86
|
end
|
@@ -18,13 +18,22 @@ module Neo4j::Mapping
|
|
18
18
|
trigger = props[:trigger].nil? ? [] : props[:trigger]
|
19
19
|
@triggers[clazz][field] = trigger.respond_to?(:each) ? trigger : [trigger]
|
20
20
|
end
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
|
22
|
+
def inherit(parent_class, subclass)
|
23
|
+
# copy all the rules
|
24
|
+
@rules[parent_class.to_s].each_pair do |field, filter|
|
25
|
+
subclass.rule field, &filter
|
26
|
+
end if @rules[parent_class.to_s]
|
27
|
+
end
|
28
|
+
|
29
|
+
def trigger_other_rules(node)
|
30
|
+
clazz = node[:_classname]
|
31
|
+
@rules[clazz].keys.each do |field|
|
32
|
+
rel_types = @triggers[clazz][field]
|
33
|
+
rel_types.each do |rel_type|
|
34
|
+
node.incoming(rel_type).each { |n| n.trigger_rules }
|
35
|
+
end
|
36
|
+
end
|
28
37
|
end
|
29
38
|
|
30
39
|
def fields_for(clazz)
|
@@ -61,12 +70,17 @@ module Neo4j::Mapping
|
|
61
70
|
end
|
62
71
|
|
63
72
|
def rule_for(clazz)
|
64
|
-
|
73
|
+
if Neo4j.ref_node.rel?(clazz)
|
74
|
+
Neo4j.ref_node._rel(:outgoing, clazz)._end_node
|
75
|
+
else
|
76
|
+
# this should be called if the rule node gets deleted
|
77
|
+
create_rule_node_for(clazz)
|
78
|
+
end
|
65
79
|
end
|
66
80
|
|
67
81
|
|
68
82
|
def on_relationship_created(rel, *)
|
69
|
-
|
83
|
+
trigger_start_node = trigger?(rel._start_node)
|
70
84
|
trigger_end_node = trigger?(rel._end_node)
|
71
85
|
# end or start node must be triggered by this event
|
72
86
|
return unless trigger_start_node || trigger_end_node
|
@@ -75,28 +89,52 @@ module Neo4j::Mapping
|
|
75
89
|
|
76
90
|
|
77
91
|
def on_property_changed(node, *)
|
78
|
-
|
92
|
+
trigger_rules(node) if trigger?(node)
|
79
93
|
end
|
80
94
|
|
81
95
|
def trigger_rules(node)
|
82
|
-
|
83
|
-
|
96
|
+
trigger_rules_for_class(node, node[:_classname])
|
97
|
+
trigger_other_rules(node)
|
98
|
+
end
|
99
|
+
|
100
|
+
def trigger_rules_for_class(node, clazz)
|
101
|
+
return if @rules[clazz].nil?
|
84
102
|
|
85
|
-
agg_node = rule_for(
|
103
|
+
agg_node = rule_for(clazz)
|
86
104
|
@rules[clazz].each_pair do |field, rule|
|
87
105
|
if run_rule(rule, node)
|
88
106
|
# is this node already included ?
|
89
|
-
|
107
|
+
unless connected?(field, agg_node, node)
|
90
108
|
agg_node.outgoing(field) << node
|
91
|
-
trigger_other_rules(node, field)
|
92
109
|
end
|
93
110
|
else
|
94
111
|
# remove old ?
|
95
|
-
|
96
|
-
trigger_other_rules(node, field)
|
112
|
+
break_connection(field, agg_node, node)
|
97
113
|
end
|
98
114
|
end
|
99
|
-
|
115
|
+
|
116
|
+
# recursively add relationships for all the parent classes with rules that also pass for this node
|
117
|
+
if clazz = eval("#{clazz}.superclass")
|
118
|
+
trigger_rules_for_class(node, clazz.to_s)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# work out if two nodes are connected by a particular relationship
|
123
|
+
# uses the end_node to start with because it's more likely to have less relationships to go through
|
124
|
+
# (just the number of superclasses it has really)
|
125
|
+
def connected?(relationship, start_node, end_node)
|
126
|
+
end_node.incoming(relationship).each do |n|
|
127
|
+
return true if n == start_node
|
128
|
+
end
|
129
|
+
false
|
130
|
+
end
|
131
|
+
|
132
|
+
# sever a direct one-to-one relationship if it exists
|
133
|
+
def break_connection(relationship, start_node, end_node)
|
134
|
+
end_node.rels(relationship).incoming.each do |r|
|
135
|
+
return r.del if r.start_node == start_node
|
136
|
+
end
|
137
|
+
end
|
100
138
|
|
101
139
|
def run_rule(rule, node)
|
102
140
|
if rule.arity != 1
|
@@ -130,10 +168,10 @@ module Neo4j::Mapping
|
|
130
168
|
# p1.young? # => true
|
131
169
|
#
|
132
170
|
def rule(name, props = {}, &block)
|
133
|
-
|
171
|
+
singelton = class << self;
|
134
172
|
self;
|
135
173
|
end
|
136
|
-
|
174
|
+
|
137
175
|
# define class methods
|
138
176
|
singelton.send(:define_method, name) do
|
139
177
|
agg_node = Rules.rule_for(self)
|
@@ -145,16 +183,20 @@ module Neo4j::Mapping
|
|
145
183
|
end
|
146
184
|
end
|
147
185
|
traversal
|
148
|
-
end
|
186
|
+
end unless respond_to?(name)
|
149
187
|
|
150
188
|
# define instance methods
|
151
189
|
self.send(:define_method, "#{name}?") do
|
152
190
|
instance_eval &block
|
153
|
-
|
191
|
+
end
|
154
192
|
|
155
193
|
Rules.add(self, name, props, &block)
|
156
194
|
end
|
157
|
-
|
195
|
+
|
196
|
+
def inherit_rules_from(clazz)
|
197
|
+
Rules.inherit(clazz, self)
|
198
|
+
end
|
199
|
+
|
158
200
|
# This is typically used for RSpecs to clean up rule nodes created by the #rule method.
|
159
201
|
# It also remove the given class method.
|
160
202
|
def delete_rules
|
@@ -34,37 +34,25 @@ module Neo4j::Mapping
|
|
34
34
|
include Neo4j::ToJava
|
35
35
|
|
36
36
|
attr_reader :to_type, :to_class, :cascade_delete_prop_name, :counter, :rel_id, :direction
|
37
|
-
CASCADE_DELETE_PROP_NAMES = {:outgoing => :_cascade_delete_outgoing, :incoming => :_cascade_delete_incoming}
|
38
37
|
|
39
|
-
def initialize(rel_id, has_one, params)
|
38
|
+
def initialize(rel_id, has_one, to_class, params)
|
40
39
|
@direction = :outgoing
|
41
40
|
@rel_id = rel_id
|
42
41
|
@to_type = rel_id
|
43
42
|
@has_one = has_one
|
44
43
|
@namespace_type = rel_id
|
45
|
-
@
|
46
|
-
@counter = params[:counter] == true
|
44
|
+
@to_class = to_class
|
47
45
|
end
|
48
46
|
|
49
47
|
def has_one?
|
50
48
|
@has_one
|
51
49
|
end
|
52
50
|
|
53
|
-
# If a counter was specified in the dsl for counting number of nodes in this relationship.
|
54
|
-
#
|
55
|
-
def counter?
|
56
|
-
@counter
|
57
|
-
end
|
58
|
-
|
59
|
-
# If cascade delete was specified for this relationship
|
60
|
-
#
|
61
|
-
def cascade_delete?
|
62
|
-
!@cascade_delete_prop_name.nil?
|
63
|
-
end
|
64
|
-
|
65
51
|
def class_and_type_from_args(args) # :nodoc:
|
66
52
|
if (args.size > 1)
|
67
53
|
return args[0], args[1]
|
54
|
+
elsif (Symbol === args[0])
|
55
|
+
return @to_class, args[0]
|
68
56
|
else
|
69
57
|
return args[0], @rel_id
|
70
58
|
end
|
@@ -73,7 +61,7 @@ module Neo4j::Mapping
|
|
73
61
|
|
74
62
|
# The actual relationship type that this DSL will use
|
75
63
|
def namespace_type
|
76
|
-
@
|
64
|
+
@namespace_type
|
77
65
|
end
|
78
66
|
|
79
67
|
def each_node(node, direction, &block)
|
@@ -90,7 +78,7 @@ module Neo4j::Mapping
|
|
90
78
|
end
|
91
79
|
|
92
80
|
def incoming_dsl
|
93
|
-
dsl = to_class._decl_rels[to_type]
|
81
|
+
dsl = @to_class._decl_rels[to_type]
|
94
82
|
raise "Unspecified outgoing relationship '#{to_type}' for incoming relationship '#{rel_id}' on class #{to_class}" if dsl.nil?
|
95
83
|
dsl
|
96
84
|
end
|
@@ -106,13 +94,18 @@ module Neo4j::Mapping
|
|
106
94
|
node._java_node.rel(dir, dsl.namespace_type)
|
107
95
|
end
|
108
96
|
|
109
|
-
def
|
97
|
+
def _all_relationships(node)
|
110
98
|
dsl = incoming? ? incoming_dsl : self
|
111
99
|
type = type_to_java(dsl.namespace_type)
|
112
100
|
dir = dir_to_java(direction)
|
113
101
|
node._java_node.getRelationships(type, dir)
|
114
102
|
end
|
115
103
|
|
104
|
+
def all_relationships(node)
|
105
|
+
dsl = incoming? ? incoming_dsl : self
|
106
|
+
Neo4j::RelationshipTraverser.new(node._java_node, [dsl.namespace_type], direction)
|
107
|
+
end
|
108
|
+
|
116
109
|
def create_relationship_to(node, other)
|
117
110
|
dsl = incoming? ? incoming_dsl : self
|
118
111
|
|
@@ -156,6 +149,7 @@ module Neo4j::Mapping
|
|
156
149
|
def to(*args)
|
157
150
|
@direction = :outgoing
|
158
151
|
@to_class, @to_type = class_and_type_from_args(args)
|
152
|
+
@namespace_type = "#{@to_class.to_s}##{@to_type.to_s}"
|
159
153
|
self
|
160
154
|
end
|
161
155
|
|
data/lib/neo4j/mapping/has_n.rb
CHANGED
@@ -6,7 +6,7 @@ module Neo4j::Mapping
|
|
6
6
|
|
7
7
|
def_delegators :@_java_node, :[]=, :[], :property?, :props, :attributes, :update, :neo_id, :id, :rels, :rel?, :to_param, :getId,
|
8
8
|
:rel, :del, :list?, :print, :print_sub, :outgoing, :incoming, :both,
|
9
|
-
:equal?, :eql?, :==, :exist?, :getRelationships, :getSingleRelationship, :
|
9
|
+
:equal?, :eql?, :==, :exist?, :getRelationships, :getSingleRelationship, :_rels, :rel
|
10
10
|
|
11
11
|
|
12
12
|
# --------------------------------------------------------------------------
|
@@ -59,8 +59,14 @@ module Neo4j::Mapping
|
|
59
59
|
c.extend Neo4j::Index::ClassMethods
|
60
60
|
|
61
61
|
def c.inherited(subclass)
|
62
|
-
subclass.node_indexer subclass
|
63
62
|
subclass.root_class subclass
|
63
|
+
|
64
|
+
# inherit the index properties
|
65
|
+
subclass.node_indexer self
|
66
|
+
|
67
|
+
# inherit the rules too
|
68
|
+
subclass.inherit_rules_from self
|
69
|
+
|
64
70
|
super
|
65
71
|
end
|
66
72
|
|
@@ -5,7 +5,7 @@ module Neo4j::Mapping
|
|
5
5
|
include Neo4j::Index
|
6
6
|
|
7
7
|
def_delegators :@_java_rel, :[]=, :[], :property?, :props, :attributes, :update, :neo_id, :id, :to_param, :getId,
|
8
|
-
:equal?, :eql?, :==, :delete, :getStartNode, :getEndNode, :getOtherNode
|
8
|
+
:equal?, :eql?, :==, :delete, :getStartNode, :getEndNode, :getOtherNode, :exist?
|
9
9
|
|
10
10
|
|
11
11
|
|
@@ -59,7 +59,7 @@ module Neo4j::Mapping
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def exist?
|
62
|
-
Neo4j::Relationship.
|
62
|
+
Neo4j::Relationship.exist?(self)
|
63
63
|
end
|
64
64
|
|
65
65
|
# A convenience operation that, given a node that is attached to this relationship, returns the other node.
|
data/lib/neo4j/node.rb
CHANGED
@@ -118,6 +118,7 @@ module Neo4j
|
|
118
118
|
# Same as load but does not return the node as a wrapped Ruby object.
|
119
119
|
#
|
120
120
|
def _load(node_id, db)
|
121
|
+
return nil if node_id.nil?
|
121
122
|
db.graph.get_node_by_id(node_id.to_i)
|
122
123
|
rescue java.lang.IllegalStateException
|
123
124
|
nil # the node has been deleted
|
@@ -111,7 +111,7 @@ module Neo4j
|
|
111
111
|
end
|
112
112
|
|
113
113
|
# Returns the raw java neo4j relationship object.
|
114
|
-
def
|
114
|
+
def _rels(dir=:both, *types)
|
115
115
|
if types.size > 1
|
116
116
|
java_types = types.inject([]) { |result, type| result << type_to_java(type) }.to_java(:'org.neo4j.graphdb.RelationshipType')
|
117
117
|
get_relationships(java_types)
|
data/lib/neo4j/rails/model.rb
CHANGED
@@ -2,6 +2,7 @@ module Neo4j
|
|
2
2
|
module Rails
|
3
3
|
class Model
|
4
4
|
include Neo4j::NodeMixin
|
5
|
+
include ActiveModel::Serializers::Xml
|
5
6
|
include ActiveModel::Validations
|
6
7
|
include ActiveModel::Dirty
|
7
8
|
include ActiveModel::MassAssignmentSecurity
|
@@ -13,7 +14,8 @@ module Neo4j
|
|
13
14
|
|
14
15
|
define_model_callbacks :create, :save, :update, :destroy
|
15
16
|
|
16
|
-
|
17
|
+
rule :all
|
18
|
+
|
17
19
|
UniquenessValidator = Neo4j::Validations::UniquenessValidator
|
18
20
|
|
19
21
|
class RecordInvalidError < RuntimeError
|
@@ -35,7 +37,6 @@ module Neo4j
|
|
35
37
|
def init_on_create(*args) # :nodoc:
|
36
38
|
super()
|
37
39
|
self.attributes=args[0] if args[0].respond_to?(:each_pair)
|
38
|
-
@_created_record = true
|
39
40
|
end
|
40
41
|
|
41
42
|
# --------------------------------------
|
@@ -119,7 +120,7 @@ module Neo4j
|
|
119
120
|
if new?
|
120
121
|
# We are updating a node that was created with the 'new' method.
|
121
122
|
# The relationship will only be kept in the Value object.
|
122
|
-
outgoing(rel_type)<<clazz.new(attr) unless reject_if?(reject_if, attr)
|
123
|
+
outgoing(rel_type) << clazz.new(attr) unless reject_if?(reject_if, attr) || (allow_destroy && attr[:_destroy] && attr[:_destroy] != '0')
|
123
124
|
else
|
124
125
|
# We have a node that was created with the #create method - has real Neo4j relationships
|
125
126
|
# does it exist ?
|
@@ -167,36 +168,40 @@ module Neo4j
|
|
167
168
|
end
|
168
169
|
|
169
170
|
def save
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
Neo4j::Rails::Transaction.fail if Neo4j::Rails::Transaction.running? && !_java_node.kind_of?(Neo4j::Rails::Value)
|
180
|
-
false
|
171
|
+
_run_save_callbacks do
|
172
|
+
if create_or_update_node
|
173
|
+
true
|
174
|
+
else
|
175
|
+
# if not valid we should rollback the transaction so that the changes does not take place.
|
176
|
+
# no point failing the transaction if we have created a model with 'new'
|
177
|
+
Neo4j::Rails::Transaction.fail if Neo4j::Rails::Transaction.running? #&& !_java_node.kind_of?(Neo4j::Rails::Value)
|
178
|
+
false
|
179
|
+
end
|
181
180
|
end
|
182
|
-
valid
|
183
181
|
end
|
184
182
|
|
185
183
|
def create_or_update_node
|
186
|
-
valid
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
184
|
+
if valid?(:save)
|
185
|
+
if new_record?
|
186
|
+
_run_create_callbacks do
|
187
|
+
if valid?(:create)
|
188
|
+
node = Neo4j::Node.new(props)
|
189
|
+
return false unless _java_node.save_nested(node)
|
190
|
+
init_on_load(node)
|
191
|
+
init_on_create
|
192
|
+
clear_changes
|
193
|
+
true
|
194
|
+
end
|
195
|
+
end
|
196
|
+
else
|
197
|
+
_run_update_callbacks do
|
198
|
+
if valid?(:update)
|
199
|
+
clear_changes
|
200
|
+
true
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
198
204
|
end
|
199
|
-
valid
|
200
205
|
end
|
201
206
|
|
202
207
|
def clear_changes
|
@@ -204,6 +209,12 @@ module Neo4j
|
|
204
209
|
@changed_attributes.clear
|
205
210
|
end
|
206
211
|
|
212
|
+
def reload(options = nil)
|
213
|
+
clear_changes
|
214
|
+
attributes = self.class.load(self.id.to_s).attributes
|
215
|
+
self
|
216
|
+
end
|
217
|
+
|
207
218
|
def save!
|
208
219
|
raise RecordInvalidError.new(self) unless save
|
209
220
|
end
|
@@ -217,15 +228,11 @@ module Neo4j
|
|
217
228
|
self
|
218
229
|
end
|
219
230
|
|
220
|
-
# Returns true if this object hasn’t been saved yet — that is, a record for the object doesn’t exist yet; otherwise, returns false.
|
221
|
-
def new_record?()
|
222
|
-
# it is new if the model has been created with either the new or create method
|
223
|
-
new? || @_created_record == true
|
224
|
-
end
|
225
|
-
|
226
231
|
def new?
|
227
232
|
_java_node.kind_of?(Neo4j::Rails::Value)
|
228
233
|
end
|
234
|
+
|
235
|
+
alias :new_record? :new?
|
229
236
|
|
230
237
|
def del
|
231
238
|
@_deleted = true
|
@@ -258,12 +265,12 @@ module Neo4j
|
|
258
265
|
wrapped
|
259
266
|
end
|
260
267
|
|
261
|
-
|
262
|
-
def
|
263
|
-
if args.
|
264
|
-
|
268
|
+
# Behave like ActiveModel
|
269
|
+
def all_with_args(*args)
|
270
|
+
if args.empty?
|
271
|
+
all_without_args
|
265
272
|
else
|
266
|
-
hits
|
273
|
+
hits = find_without_checking_for_id(*args)
|
267
274
|
# We need to save this so that the Rack Neo4j::Rails:LuceneConnection::Closer can close it
|
268
275
|
Thread.current[:neo4j_lucene_connection] ||= []
|
269
276
|
Thread.current[:neo4j_lucene_connection] << hits
|
@@ -271,6 +278,19 @@ module Neo4j
|
|
271
278
|
end
|
272
279
|
end
|
273
280
|
|
281
|
+
alias_method_chain :all, :args
|
282
|
+
|
283
|
+
# Handle Model.find(params[:id])
|
284
|
+
def find_with_checking_for_id(*args)
|
285
|
+
if args.length == 1 && String === args[0] && args[0].to_i != 0
|
286
|
+
load(*args)
|
287
|
+
else
|
288
|
+
all_with_args(*args).first
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
alias_method_chain :find, :checking_for_id
|
293
|
+
|
274
294
|
def load(*ids)
|
275
295
|
result = ids.map { |id| Neo4j::Node.load(id) }
|
276
296
|
if ids.length == 1
|
@@ -283,16 +303,12 @@ module Neo4j
|
|
283
303
|
|
284
304
|
alias_method :_orig_create, :create
|
285
305
|
|
286
|
-
def create(*)
|
287
|
-
|
288
|
-
model.save
|
289
|
-
model
|
306
|
+
def create(*args)
|
307
|
+
new(*args).tap { |o| o.save }
|
290
308
|
end
|
291
309
|
|
292
310
|
def create!(*args)
|
293
|
-
|
294
|
-
model.save!
|
295
|
-
model
|
311
|
+
new(*args).tap { |o| o.save! }
|
296
312
|
end
|
297
313
|
|
298
314
|
tx_methods :create, :create!
|
@@ -338,4 +354,3 @@ module Neo4j
|
|
338
354
|
|
339
355
|
end
|
340
356
|
end
|
341
|
-
|
@@ -5,16 +5,16 @@ module Neo4j
|
|
5
5
|
super(options.reverse_merge(:case_sensitive => true))
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
raise "Can't validate property #{attribute} on class #{clazz} since there is no :exact lucene index on that property"
|
8
|
+
def setup(klass)
|
9
|
+
@attributes.each do |attribute|
|
10
|
+
if klass.index_type_for(attribute) != :exact
|
11
|
+
raise "Can't validate property #{attribute} on class #{klass} since there is no :exact lucene index on that property or the index declaration #{attribute} comes after the validation declaration in #{klass} (try to move it before the validation rules)"
|
12
|
+
end
|
14
13
|
end
|
14
|
+
end
|
15
15
|
|
16
|
-
|
17
|
-
if
|
16
|
+
def validate_each(record, attribute, value)
|
17
|
+
if record.class.find("#{attribute}: #{value}")
|
18
18
|
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
|
19
19
|
end
|
20
20
|
end
|
data/lib/neo4j/rails/value.rb
CHANGED
data/lib/neo4j/relationship.rb
CHANGED
@@ -36,6 +36,12 @@ module Neo4j
|
|
36
36
|
self
|
37
37
|
end
|
38
38
|
|
39
|
+
|
40
|
+
# Returns true if the relationship exists
|
41
|
+
def exist?
|
42
|
+
Neo4j::Relationship.exist?(self)
|
43
|
+
end
|
44
|
+
|
39
45
|
# Loads the Ruby wrapper for this node
|
40
46
|
# If there is no _classname property for this node then it will simply return itself.
|
41
47
|
# Same as Neo4j::Node.load_wrapper(node)
|
@@ -130,8 +136,24 @@ module Neo4j
|
|
130
136
|
# create is the same as new
|
131
137
|
alias_method :create, :new
|
132
138
|
|
139
|
+
# Loads a relationship or wrapped relationship given a native java relationship or an id.
|
140
|
+
# If there is a Ruby wrapper for the node then it will create a Ruby object that will
|
141
|
+
# wrap the java node (see Neo4j::RelationshipMixin).
|
142
|
+
#
|
143
|
+
# If the relationship does not exist it will return nil
|
144
|
+
#
|
133
145
|
def load(rel_id, db = Neo4j.started_db)
|
134
|
-
|
146
|
+
rel = _load(rel_id, db)
|
147
|
+
return nil if rel.nil?
|
148
|
+
rel.wrapper
|
149
|
+
end
|
150
|
+
|
151
|
+
# Same as load but does not return the node as a wrapped Ruby object.
|
152
|
+
#
|
153
|
+
def _load(rel_id, db)
|
154
|
+
rel = db.graph.get_relationship_by_id(rel_id.to_i)
|
155
|
+
rel.hasProperty('_classname') # since we want a IllegalStateException which is otherwise not triggered
|
156
|
+
rel
|
135
157
|
rescue java.lang.IllegalStateException
|
136
158
|
nil # the node has been deleted
|
137
159
|
rescue org.neo4j.graphdb.NotFoundException
|
@@ -4,59 +4,83 @@ module Neo4j
|
|
4
4
|
include Enumerable
|
5
5
|
include ToJava
|
6
6
|
|
7
|
-
def initialize(node, types,
|
8
|
-
@node
|
7
|
+
def initialize(node, types, direction)
|
8
|
+
@node = node
|
9
9
|
if types.size > 1
|
10
10
|
@types = types.inject([]) { |result, type| result << type_to_java(type) }.to_java(:'org.neo4j.graphdb.RelationshipType')
|
11
11
|
elsif types.size == 1
|
12
12
|
@type = type_to_java(types[0])
|
13
13
|
end
|
14
|
-
|
15
|
-
@dir = dir_to_java(dir)
|
14
|
+
@direction = direction
|
16
15
|
end
|
17
16
|
|
18
17
|
def to_s
|
19
18
|
if @type
|
20
|
-
"#{self.class} [type: #{@type} dir:#{@
|
19
|
+
"#{self.class} [type: #{@type} dir:#{@direction}]"
|
21
20
|
elsif @types
|
22
|
-
"#{self.class} [types: #{@types.join(',')} dir:#{@
|
21
|
+
"#{self.class} [types: #{@types.join(',')} dir:#{@direction}]"
|
23
22
|
else
|
24
|
-
"#{self.class} [types: ANY dir:#{@
|
23
|
+
"#{self.class} [types: ANY dir:#{@direction}]"
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
28
27
|
def each
|
29
|
-
|
28
|
+
iter = iterator
|
29
|
+
while (iter.hasNext())
|
30
|
+
rel = iter.next
|
31
|
+
yield rel.wrapper if match_to_other?(rel)
|
32
|
+
end
|
30
33
|
end
|
31
34
|
|
32
35
|
def iterator
|
33
36
|
if @types
|
34
37
|
@node.get_relationships(@types).iterator
|
35
38
|
elsif @type
|
36
|
-
@node.get_relationships(@type, @
|
39
|
+
@node.get_relationships(@type, dir_to_java(@direction))
|
40
|
+
else
|
41
|
+
@node.get_relationships(dir_to_java(@direction))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def match_to_other?(rel)
|
46
|
+
if @to_other.nil?
|
47
|
+
true
|
48
|
+
elsif @direction == :outgoing
|
49
|
+
rel._end_node == @to_other
|
50
|
+
elsif @direction == :incoming
|
51
|
+
rel._start_node == @to_other
|
37
52
|
else
|
38
|
-
@
|
53
|
+
rel._start_node == @to_other || rel._end_node == @to_other
|
39
54
|
end
|
40
55
|
end
|
41
56
|
|
57
|
+
def to_other(to_other)
|
58
|
+
@to_other = to_other
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
def del
|
63
|
+
each { |rel| rel.del }
|
64
|
+
end
|
65
|
+
|
42
66
|
def size
|
43
67
|
[*self].size
|
44
68
|
end
|
45
69
|
|
46
70
|
def both
|
47
|
-
@
|
71
|
+
@direction = :both
|
48
72
|
self
|
49
73
|
end
|
50
74
|
|
51
75
|
def incoming
|
52
76
|
raise "Not allowed calling incoming when finding several relationships types" if @types
|
53
|
-
@
|
77
|
+
@direction = :incoming
|
54
78
|
self
|
55
79
|
end
|
56
80
|
|
57
81
|
def outgoing
|
58
82
|
raise "Not allowed calling outgoing when finding several relationships types" if @types
|
59
|
-
@
|
83
|
+
@direction = :outgoing
|
60
84
|
self
|
61
85
|
end
|
62
86
|
|
data/lib/neo4j/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Neo4j
|
2
|
-
VERSION = "1.0.0.beta.
|
3
|
-
end
|
2
|
+
VERSION = "1.0.0.beta.16"
|
3
|
+
end
|
metadata
CHANGED
@@ -7,8 +7,8 @@ version: !ruby/object:Gem::Version
|
|
7
7
|
- 0
|
8
8
|
- 0
|
9
9
|
- beta
|
10
|
-
-
|
11
|
-
version: 1.0.0.beta.
|
10
|
+
- 16
|
11
|
+
version: 1.0.0.beta.16
|
12
12
|
platform: ruby
|
13
13
|
authors:
|
14
14
|
- Andreas Ronge
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-10-
|
19
|
+
date: 2010-10-28 00:00:00 +02:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|