/
relation_spec.rb
452 lines (349 loc) · 11.4 KB
/
relation_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
$LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../../lib")
$LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/..")
require 'neo4j'
require 'neo4j/spec_helper'
describe "Neo4j::Node#relations " do
before(:all) do
start
end
after(:all) do
stop
end
# ----------------------------------------------------------------------------
# adding relations with <<
#
describe '<< operator' do
before(:all) do
undefine_class :TestNode # make sure it is not already defined
class TestNode
include Neo4j::NodeMixin
has_n :friends
has_n :parents
end
end
it "should add a node to a relation" do
t1 = TestNode.new
t2 = TestNode.new
# when
t1.friends << t2
# then
t1.friends.to_a.should include(t2)
end
it "should add relations of different types to other nodes" do
me = TestNode.new
f1 = TestNode.new
p1 = TestNode.new
me.friends << f1
me.parents << p1
# then
me.friends.to_a.should include(f1)
me.friends.to_a.size.should == 1
me.parents.to_a.should include(p1)
me.parents.to_a.size.should == 1
end
it "should be none symmetric (if a is friend to b then b does not have to be friend to a)" do
t1 = TestNode.new
t2 = TestNode.new
t1.friends << t2
# then
t1.friends.to_a.should include(t2)
t2.friends.to_a.should_not include(t1)
end
it "should allow to chain << operations in one line" do
# given
t1 = TestNode.new
t2 = TestNode.new
t3 = TestNode.new
t1.friends << t2 << t3
# then t2 should be a friend of t1
t1.friends.to_a.should include(t2,t3)
end
it "should be allowed in subclasses" do
undefine_class :SubNode # make sure it is not already defined
class SubNode < TestNode; end
sub = SubNode.new
t = TestNode.new
sub.friends << t
# then
sub.friends.to_a.should include(t)
end
end
# ----------------------------------------------------------------------------
# traversing outgoing and incoming nodes
#
describe '#relations traversing outgoing and incoming nodes' do
before(:all) do
undefine_class :TestNode # make sure it is not already defined
class TestNode
include Neo4j::NodeMixin
has_n :friends
has_n :parents
end
end
it "should find all outgoing nodes" do
# given
t1 = TestNode.new
t2 = TestNode.new
t1.friends << t2
# when
outgoing = t1.relations.outgoing.to_a
# then
outgoing.size.should == 1
outgoing[0].end_node.should == t2
outgoing[0].start_node.should == t1
end
it "should find all incoming nodes" do
t1 = TestNode.new
t2 = TestNode.new
t1.friends << t2
outgoing = t2.relations.incoming.to_a
outgoing.size.should == 2 # 2 since we also have a relationship to ref node
outgoing[1].end_node.should == t2
outgoing[1].start_node.should == t1
end
it "should find no incoming or outgoing nodes when there are none" do
t1 = TestNode.new
t2 = TestNode.new
t2.relations.incoming.to_a.size.should == 1 # since we also have a relationship to ref node
t2.relations.outgoing.to_a.size.should == 0
end
it "should make sure that incoming nodes are not found in outcoming nodes" do
t1 = TestNode.new
t2 = TestNode.new
t1.friends << t2
t1.relations.incoming.to_a.size.should == 1 # since we also have a relationship to ref node
t2.relations.outgoing.to_a.size.should == 0
end
it "should find both incoming and outgoing nodes" do
t1 = TestNode.new
t2 = TestNode.new
t1.friends << t2
t1.relations.nodes.to_a.should include(t2)
t2.relations.nodes.to_a.should include(t1)
end
it "should find several both incoming and outgoing nodes" do
t1 = TestNode.new
t2 = TestNode.new
t3 = TestNode.new
t1.friends << t2
t1.friends << t3
t1.relations.nodes.to_a.should include(t2,t3)
t1.relations.outgoing.nodes.to_a.should include(t2,t3)
t2.relations.incoming.nodes.to_a.should include(t1)
t3.relations.incoming.nodes.to_a.should include(t1)
t1.relations.nodes.to_a.size.should == 3 # since we also have a relationship to ref node
end
it "should find incomming nodes of a specific type" do
t1 = TestNode.new
t2 = TestNode.new
t3 = TestNode.new
t1.friends << t2
t1.friends << t3
t1.relations.outgoing(:friends).nodes.to_a.should include(t2,t3)
t2.relations.incoming(:friends).nodes.to_a.should include(t1)
t3.relations.incoming(:friends).nodes.to_a.should include(t1)
end
end
describe "traversing nodes of any depth" do
before(:all) do
undefine_class :PersonNode
class PersonNode
include Neo4j::NodeMixin
property :name
has_n :friends
end
@n0 = PersonNode.new
@n1 = PersonNode.new
@n11 = PersonNode.new
@n111 = PersonNode.new
@n12 = PersonNode.new
@n112 = PersonNode.new
@n1121 = PersonNode.new
@n0.friends << @n1 << @n12
@n1.friends << @n11 << @n12
@n11.friends << @n111 << @n112
@n112.friends << @n1121
end
it "should be possible with node.friends.depth(2).each" do
nodes = @n1.friends.depth(2)
nodes.should include(@n11,@n12,@n112)
nodes.should_not include(@n0,@n1,@n1121)
end
it "should be possible with node.friends.depth(3).each" do
nodes = @n1.friends.depth(3)
nodes.should include(@n11,@n12,@n112, @n1121)
nodes.should_not include(@n0,@n1)
end
it "should be possible with node.friends.depth(:all).each" do
pending
nodes = @n1.friends.depth(:all)
nodes.should include(@n11,@n12,@n112, @n1121)
nodes.should_not include(@n0,@n1)
end
it "should get all nodes two levels deep (for levels(2))" do
pending
nodes = @n1.relations.outgoing(:friends).levels(2)
@n1.friends.levels
nodes.should include(@n11,@n12,@n112)
nodes.should_not include(@n0,@n1,@n1121)
end
it "should get all nodes (for levels(:all))" do
pending
nodes = @n1.relations.outgoing(:friends).levels(:all)
nodes.should include(@n11,@n12,@n112,@n1121)
nodes.should_not include(@n0,@n1)
end
end
describe "#has_one to #has_n" do
before(:all) do
undefine_class :Person, :Address
class Address
end
class Person
include Neo4j::NodeMixin
has_one(:address).to(Address)
end
class Address
include Neo4j::NodeMixin
property :city, :road
has_n(:people).from(Person, :address)
end
end
it "should create a relationship with assignment like node1.rel = node2" do
# given
p = Person.new
# when
p.address = Address.new {|a| a.city = 'malmoe'; a.road = 'my road'}
# then
p.address.should be_kind_of(Address)
p.address.people.to_a.size.should == 1
p.address.people.to_a.should include(p)
end
it "should allow to find the relationship with a simple node1.rel (no traversal)" do
a = Address.new
p = Person.new
# when
a.people << p
# then
p.address.should == a
end
end
describe "#has_n to #has_one" do
before(:all) do
undefine_class :Customer, :Order, :CustOrderRel
class Customer; end
class Order
include Neo4j::NodeMixin
property :date, :order_id
has_one(:customer).from(Customer, :orders)
end
class CustOrderRel
include Neo4j::RelationMixin
property :my_prop
end
class Customer
include Neo4j::NodeMixin
property :age, :name
# TODO should be easier to say the thing below
has_n(:orders).relation(CustOrderRel)
end
end
it "should contain the order when customer.orders << order" do
# given
customer = Customer.new
order = Order.new
# when
customer.orders << order
# then
customer.orders.to_a.should include(order)
customer.orders.to_a.size == 1
end
it "should allow to set the relationship on an incoming node" do
# given
customer = Customer.new
order = Order.new
# when
order.customer = customer
# then
customer.orders.to_a.should include(order)
customer.orders.to_a.size == 1
end
it "should allow to set a property on the customer-order relationship" do
# given
customer = Customer.new
order = Order.new
relation = customer.orders.new(order) # another way of adding a relationship
# when
relation.my_prop = 'a property'
# then
relation.my_prop.should == 'a property'
end
it "should not contain the order when the customer-order relation has been deleted" do
# given
customer = Customer.new
order = Order.new
relation = customer.orders.new(order) # another way of adding a relationship
# when
relation.delete
# then
customer.orders.to_a.should_not include(order)
end
it "should find the order using a filter: customer.orders{ order_id == '2'}" do
# given
customer = Customer.new
order1 = Order.new{|n| n.order_id = '1'}
order2 = Order.new{|n| n.order_id = '2'}
order3 = Order.new{|n| n.order_id = '3'}
customer.orders << order1 << order2 << order3
# when
result = customer.orders{ order_id == '2'}.to_a
# then
result.should include(order2)
result.size.should == 1
end
end
describe '#relations, creating new' do
before(:all) do
class CustomerOrderRelation
include Neo4j::RelationMixin
property :prio
end
class Customer
include Neo4j::NodeMixin
has_n(:orders).relation(CustomerOrderRelation)
has_n :friends
end
class Order
include Neo4j::NodeMixin
end
end
it "should be possible to create a new relation of the specified type" do
c = Customer.new
o = Order.new
r = c.orders.new(o)
r.should be_kind_of(CustomerOrderRelation)
end
it "should be possible to set a property on relationship (not DynamicRelation)" do
c = Customer.new
o = Order.new
r = c.orders.new(o)
r.prio = 'important'
r.prio.should == 'important'
c.relations.outgoing(:orders)[o].prio.should == 'important'
end
it "should be possible to read an unset property on relationship (not DynamicRelation)" do
c = Customer.new
o = Order.new
r = c.orders.new(o)
r.prio.should == nil
end
it "should load the correct relation class when traversing relationships" do
c = Customer.new
o1 = Order.new
o2 = Order.new
c.orders << o1 << o2
c.relations.outgoing(:orders).each {|r| r.should be_kind_of(CustomerOrderRelation) }
end
it "can not have a relationship to a none Neo::Node"
end
end