mongo_mapper 0.15.1 → 0.15.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +6 -0
- data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +3 -1
- data/lib/mongo_mapper/plugins/associations/proxy.rb +6 -2
- data/lib/mongo_mapper/plugins/dirty.rb +2 -2
- data/lib/mongo_mapper/plugins/embedded_document.rb +1 -1
- data/lib/mongo_mapper/plugins/keys.rb +3 -5
- data/lib/mongo_mapper/plugins/scopes.rb +19 -3
- data/lib/mongo_mapper/version.rb +1 -1
- data/spec/examples.txt +1685 -1674
- data/spec/functional/associations/belongs_to_proxy_spec.rb +18 -0
- data/spec/functional/associations/one_embedded_proxy_spec.rb +28 -0
- data/spec/functional/associations/one_proxy_spec.rb +11 -1
- data/spec/functional/dirty_spec.rb +21 -0
- data/spec/functional/dirty_with_callbacks_spec.rb +59 -0
- data/spec/functional/scopes_spec.rb +88 -0
- data/spec/unit/associations/proxy_spec.rb +12 -0
- metadata +3 -2
@@ -269,4 +269,22 @@ describe "BelongsToProxy" do
|
|
269
269
|
end.should_not raise_error
|
270
270
|
end
|
271
271
|
end
|
272
|
+
|
273
|
+
context "foreign_key=" do
|
274
|
+
it "should reset parent when foreign key is changed" do
|
275
|
+
post = @post_class.create!
|
276
|
+
comment = @comment_class.create!(post: post)
|
277
|
+
another_post = @post_class.create!
|
278
|
+
|
279
|
+
comment.post.should == post
|
280
|
+
|
281
|
+
comment.post_id = another_post.id
|
282
|
+
|
283
|
+
comment.post.should == another_post
|
284
|
+
|
285
|
+
comment.post_id = nil
|
286
|
+
|
287
|
+
comment.post.should == nil
|
288
|
+
end
|
289
|
+
end
|
272
290
|
end
|
@@ -97,4 +97,32 @@ describe "OneEmbeddedProxy" do
|
|
97
97
|
post.author.address.id.should_not be_nil
|
98
98
|
end
|
99
99
|
|
100
|
+
it "should keep the reference to assigned document" do
|
101
|
+
@post_class.one(:author, :class => @author_class)
|
102
|
+
post = @post_class.new
|
103
|
+
new_author = @author_class.new
|
104
|
+
post.author = new_author
|
105
|
+
new_author.name = 'Frank'
|
106
|
+
|
107
|
+
post.author.name.should == 'Frank'
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should update references for parent and root" do
|
111
|
+
@post_class.key(:author_name, String)
|
112
|
+
@post_class.one(:author, :class => @author_class)
|
113
|
+
@post_class.before_save do
|
114
|
+
self.author_name = author.name
|
115
|
+
end
|
116
|
+
|
117
|
+
author = @author_class.new
|
118
|
+
@post_class.create!(author: author)
|
119
|
+
author.save!
|
120
|
+
|
121
|
+
post = @post_class.create!(author: author)
|
122
|
+
post.author.name = 'Frank'
|
123
|
+
post.author.save!
|
124
|
+
|
125
|
+
post.author.name.should == 'Frank'
|
126
|
+
post.author_name.should == 'Frank'
|
127
|
+
end
|
100
128
|
end
|
@@ -403,4 +403,14 @@ describe "OneProxy" do
|
|
403
403
|
article.paper_id.should == @paper.id
|
404
404
|
end
|
405
405
|
end
|
406
|
-
|
406
|
+
|
407
|
+
it "should keep the reference to assigned document" do
|
408
|
+
@post_class.one(:author, :class => @author_class)
|
409
|
+
post = @post_class.new
|
410
|
+
new_author = @author_class.new
|
411
|
+
post.author = new_author
|
412
|
+
new_author.name = 'Frank'
|
413
|
+
|
414
|
+
post.author.name.should == 'Frank'
|
415
|
+
end
|
416
|
+
end
|
@@ -280,6 +280,27 @@ describe "Dirty" do
|
|
280
280
|
end
|
281
281
|
end
|
282
282
|
|
283
|
+
context "Document having Array key with typecast option" do
|
284
|
+
before do
|
285
|
+
@author_id = BSON::ObjectId.new
|
286
|
+
@doc = Doc('Book') { key :author_ids, Array, typecast: "ObjectId" }
|
287
|
+
@doc.plugin MongoMapper::Plugins::Dirty
|
288
|
+
@book = @doc.create!(author_ids: [@author_id])
|
289
|
+
end
|
290
|
+
|
291
|
+
context "changed" do
|
292
|
+
it "should be empty if assigned the same array" do
|
293
|
+
@book.author_ids = [@author_id]
|
294
|
+
@book.changed.should be_empty
|
295
|
+
end
|
296
|
+
|
297
|
+
it "should be empty if assigned the same but before-typecasted array" do
|
298
|
+
@book.author_ids = [@author_id.to_s]
|
299
|
+
@book.changed.should be_empty
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
283
304
|
context "Embedded documents" do
|
284
305
|
before do
|
285
306
|
@edoc = EDoc('Duck') { key :name, String }
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'DirtyWithCallbacks' do
|
4
|
+
it 'should update its changes/previous_changes before after_create/after_update callbacks' do
|
5
|
+
history = {}
|
6
|
+
|
7
|
+
document = Doc {
|
8
|
+
key :x, String
|
9
|
+
|
10
|
+
after_save {
|
11
|
+
history[:after_save] = {
|
12
|
+
changes: changes,
|
13
|
+
previous_changes: previous_changes,
|
14
|
+
}
|
15
|
+
}
|
16
|
+
after_create {
|
17
|
+
history[:after_create] = {
|
18
|
+
changes: changes,
|
19
|
+
previous_changes: previous_changes,
|
20
|
+
}
|
21
|
+
}
|
22
|
+
after_update {
|
23
|
+
history[:after_update] = {
|
24
|
+
changes: changes,
|
25
|
+
previous_changes: previous_changes,
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
d = document.new(x: 'hello')
|
31
|
+
d.save
|
32
|
+
|
33
|
+
history.should == {
|
34
|
+
after_save: {
|
35
|
+
changes: {},
|
36
|
+
previous_changes: {'x' => [nil, 'hello']},
|
37
|
+
},
|
38
|
+
after_create: {
|
39
|
+
changes: {},
|
40
|
+
previous_changes: {'x' => [nil, 'hello']},
|
41
|
+
},
|
42
|
+
}
|
43
|
+
history.clear
|
44
|
+
|
45
|
+
d.x = 'world'
|
46
|
+
d.save!
|
47
|
+
|
48
|
+
history.should == {
|
49
|
+
after_save: {
|
50
|
+
changes: {},
|
51
|
+
previous_changes: {'x' => ['hello', 'world']},
|
52
|
+
},
|
53
|
+
after_update: {
|
54
|
+
changes: {},
|
55
|
+
previous_changes: {'x' => ['hello', 'world']},
|
56
|
+
},
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
@@ -200,6 +200,19 @@ describe "Scopes" do
|
|
200
200
|
Blog.scopes.keys.map(&:to_s).should =~ %w(by_slug by_title published)
|
201
201
|
end
|
202
202
|
end
|
203
|
+
|
204
|
+
context 'with predefined class method name' do
|
205
|
+
it 'should raise ArgumentError' do
|
206
|
+
bad_names = %i(private public protected allocate new name parent superclass reload)
|
207
|
+
bad_names.each do |bad_name|
|
208
|
+
-> {
|
209
|
+
Doc() do
|
210
|
+
scope bad_name, -> {}
|
211
|
+
end
|
212
|
+
}.should raise_error(ArgumentError, /You tried to define a scope named "#{bad_name}"/)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
203
216
|
end
|
204
217
|
|
205
218
|
describe "with_scope" do
|
@@ -434,4 +447,79 @@ describe "Scopes" do
|
|
434
447
|
@klass.unsent.sorted.all.should == [two_days_ago, one_day_ago]
|
435
448
|
end
|
436
449
|
end
|
450
|
+
|
451
|
+
describe "thread safety" do
|
452
|
+
before do
|
453
|
+
@klass = Doc do
|
454
|
+
key :name, String
|
455
|
+
end
|
456
|
+
|
457
|
+
@threads = []
|
458
|
+
end
|
459
|
+
|
460
|
+
after do
|
461
|
+
@threads.each do |thread|
|
462
|
+
thread.kill
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
def make_thread(&block)
|
467
|
+
Thread.new(&block).tap do |thread|
|
468
|
+
@threads << thread
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
def wait_for_threads!
|
473
|
+
@threads.each { |t| t.join }
|
474
|
+
end
|
475
|
+
|
476
|
+
it "should not taint another thread's active scopes" do
|
477
|
+
count_active_scopes = nil
|
478
|
+
second_thread_run = false
|
479
|
+
|
480
|
+
make_thread do
|
481
|
+
@klass.with_scope(name: 'foo') do
|
482
|
+
loop do
|
483
|
+
sleep Float::EPSILON
|
484
|
+
break if second_thread_run
|
485
|
+
end
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
make_thread do
|
490
|
+
count_active_scopes = @klass.active_scopes.length
|
491
|
+
second_thread_run = true
|
492
|
+
end
|
493
|
+
|
494
|
+
wait_for_threads!
|
495
|
+
|
496
|
+
count_active_scopes.should == 0
|
497
|
+
end
|
498
|
+
|
499
|
+
it "should not taint another thread's count method" do
|
500
|
+
@klass.create!(name: 'foo')
|
501
|
+
@klass.create!(name: 'bar')
|
502
|
+
|
503
|
+
klass_count = nil
|
504
|
+
second_thread_run = false
|
505
|
+
|
506
|
+
make_thread do
|
507
|
+
@klass.with_scope(name: 'foo') do
|
508
|
+
loop do
|
509
|
+
sleep Float::EPSILON
|
510
|
+
break if second_thread_run
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
make_thread do
|
516
|
+
klass_count = @klass.count
|
517
|
+
second_thread_run = true
|
518
|
+
end
|
519
|
+
|
520
|
+
wait_for_threads!
|
521
|
+
|
522
|
+
klass_count.should == 2
|
523
|
+
end
|
524
|
+
end
|
437
525
|
end
|
@@ -95,5 +95,17 @@ describe "Proxy" do
|
|
95
95
|
p = Proc.new {|x| x+1}
|
96
96
|
@proxy.send(:collect, &p).should == [2,3]
|
97
97
|
end
|
98
|
+
|
99
|
+
it "should not respond to private method" do
|
100
|
+
@proxy.reload # To load @proxy.target
|
101
|
+
@proxy.target.extend(Module.new do
|
102
|
+
private
|
103
|
+
|
104
|
+
def private_foo
|
105
|
+
end
|
106
|
+
end)
|
107
|
+
|
108
|
+
lambda { @proxy.private_foo }.should raise_error(NoMethodError, /private method `private_foo' called/)
|
109
|
+
end
|
98
110
|
end
|
99
111
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongo_mapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.15.
|
4
|
+
version: 0.15.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2021-02-01 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: mongo
|
@@ -224,6 +224,7 @@ files:
|
|
224
224
|
- spec/functional/callbacks_spec.rb
|
225
225
|
- spec/functional/counter_cache_spec.rb
|
226
226
|
- spec/functional/dirty_spec.rb
|
227
|
+
- spec/functional/dirty_with_callbacks_spec.rb
|
227
228
|
- spec/functional/document_spec.rb
|
228
229
|
- spec/functional/dumpable_spec.rb
|
229
230
|
- spec/functional/dynamic_querying_spec.rb
|