neo4j 1.0.0.beta.15 → 1.0.0.beta.16
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/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
|