mongo_mapper 0.11.0 → 0.11.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/mongo_mapper.rb +1 -0
- data/lib/mongo_mapper/connection.rb +7 -4
- data/lib/mongo_mapper/document.rb +1 -0
- data/lib/mongo_mapper/embedded_document.rb +1 -0
- data/lib/mongo_mapper/extensions/time.rb +1 -2
- data/lib/mongo_mapper/plugins/associations/base.rb +5 -1
- data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +25 -1
- data/lib/mongo_mapper/plugins/associations/single_association.rb +1 -0
- data/lib/mongo_mapper/plugins/callbacks.rb +4 -0
- data/lib/mongo_mapper/plugins/embedded_callbacks.rb +1 -0
- data/lib/mongo_mapper/plugins/inspect.rb +1 -1
- data/lib/mongo_mapper/plugins/modifiers.rb +37 -25
- data/lib/mongo_mapper/plugins/querying.rb +4 -11
- data/lib/mongo_mapper/plugins/querying/plucky_methods.rb +9 -3
- data/lib/mongo_mapper/plugins/touch.rb +18 -0
- data/lib/mongo_mapper/version.rb +1 -1
- data/test/functional/associations/test_many_documents_proxy.rb +62 -0
- data/test/functional/test_modifiers.rb +147 -96
- data/test/functional/test_querying.rb +37 -0
- data/test/functional/test_timestamps.rb +5 -5
- data/test/functional/test_touch.rb +125 -0
- data/test/unit/associations/test_base.rb +10 -0
- data/test/unit/test_extensions.rb +4 -4
- data/test/unit/test_inspect.rb +20 -0
- data/test/unit/test_mongo_mapper.rb +10 -0
- data/test/unit/test_time_zones.rb +5 -0
- metadata +16 -16
data/lib/mongo_mapper.rb
CHANGED
@@ -56,6 +56,7 @@ module MongoMapper
|
|
56
56
|
autoload :Timestamps, 'mongo_mapper/plugins/timestamps'
|
57
57
|
autoload :Userstamps, 'mongo_mapper/plugins/userstamps'
|
58
58
|
autoload :Validations, 'mongo_mapper/plugins/validations'
|
59
|
+
autoload :Touch, 'mongo_mapper/plugins/touch'
|
59
60
|
|
60
61
|
module Associations
|
61
62
|
autoload :Base, 'mongo_mapper/plugins/associations/base'
|
@@ -3,6 +3,11 @@ require 'uri'
|
|
3
3
|
|
4
4
|
module MongoMapper
|
5
5
|
module Connection
|
6
|
+
@@connection = nil
|
7
|
+
@@database = nil
|
8
|
+
@@database_name = nil
|
9
|
+
@@config = nil
|
10
|
+
|
6
11
|
# @api public
|
7
12
|
def connection
|
8
13
|
@@connection ||= Mongo::Connection.new
|
@@ -26,9 +31,7 @@ module MongoMapper
|
|
26
31
|
|
27
32
|
# @api public
|
28
33
|
def database
|
29
|
-
if @@database_name.blank?
|
30
|
-
raise 'You forgot to set the default database name: MongoMapper.database = "foobar"'
|
31
|
-
end
|
34
|
+
return nil if @@database_name.blank?
|
32
35
|
|
33
36
|
@@database ||= MongoMapper.connection.db(@@database_name)
|
34
37
|
end
|
@@ -44,7 +47,7 @@ module MongoMapper
|
|
44
47
|
|
45
48
|
# @api private
|
46
49
|
def config_for_environment(environment)
|
47
|
-
env = config[environment] || {}
|
50
|
+
env = config[environment.to_s] || {}
|
48
51
|
return env if env['uri'].blank?
|
49
52
|
|
50
53
|
uri = URI.parse(env['uri'])
|
@@ -29,6 +29,7 @@ module MongoMapper
|
|
29
29
|
include Plugins::Serialization
|
30
30
|
include Plugins::Timestamps
|
31
31
|
include Plugins::Userstamps
|
32
|
+
include Plugins::Touch
|
32
33
|
include Plugins::Validations
|
33
34
|
include Plugins::EmbeddedCallbacks
|
34
35
|
include Plugins::Callbacks # for now callbacks needs to be after validations
|
@@ -8,8 +8,7 @@ module MongoMapper
|
|
8
8
|
else
|
9
9
|
time_class = ::Time.try(:zone).present? ? ::Time.zone : ::Time
|
10
10
|
time = value.is_a?(::Time) ? value : time_class.parse(value.to_s)
|
11
|
-
|
12
|
-
at(time.to_i).utc if time
|
11
|
+
at(time.to_f).utc if time # ensure milliseconds are preserved with to_f (issue #308)
|
13
12
|
end
|
14
13
|
end
|
15
14
|
|
@@ -6,7 +6,7 @@ module MongoMapper
|
|
6
6
|
attr_reader :name, :options, :query_options
|
7
7
|
|
8
8
|
# Options that should not be considered MongoDB query options/criteria
|
9
|
-
AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :polymorphic, :autosave]
|
9
|
+
AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :polymorphic, :autosave, :touch]
|
10
10
|
|
11
11
|
def initialize(name, options={}, &extension)
|
12
12
|
@name, @options, @query_options, @original_options = name.to_sym, {}, {}, options
|
@@ -39,6 +39,10 @@ module MongoMapper
|
|
39
39
|
klass.embeddable?
|
40
40
|
end
|
41
41
|
|
42
|
+
def touch?
|
43
|
+
!!@options[:touch]
|
44
|
+
end
|
45
|
+
|
42
46
|
def type_key_name
|
43
47
|
"_type"
|
44
48
|
end
|
@@ -18,12 +18,36 @@ module MongoMapper
|
|
18
18
|
def setup(model)
|
19
19
|
model.key foreign_key, ObjectId unless model.key?(foreign_key)
|
20
20
|
super
|
21
|
+
add_touch_callbacks if touch?
|
21
22
|
end
|
22
23
|
|
23
24
|
def autosave?
|
24
25
|
options.fetch(:autosave, false)
|
25
26
|
end
|
27
|
+
|
28
|
+
def add_touch_callbacks
|
29
|
+
name = self.name
|
30
|
+
method_name = "belongs_to_touch_after_save_or_destroy_for_#{name}"
|
31
|
+
touch = options.fetch(:touch)
|
32
|
+
|
33
|
+
@model.send(:define_method, method_name) do
|
34
|
+
record = send(name)
|
35
|
+
|
36
|
+
unless record.nil?
|
37
|
+
if touch == true
|
38
|
+
record.touch
|
39
|
+
else
|
40
|
+
record.touch(touch)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
@model.after_save(method_name)
|
46
|
+
@model.after_touch(method_name)
|
47
|
+
@model.after_destroy(method_name)
|
48
|
+
|
49
|
+
end
|
26
50
|
end
|
27
51
|
end
|
28
52
|
end
|
29
|
-
end
|
53
|
+
end
|
@@ -7,7 +7,7 @@ module MongoMapper
|
|
7
7
|
def inspect(include_nil = false)
|
8
8
|
keys = include_nil ? key_names : attributes.keys
|
9
9
|
attributes_as_nice_string = keys.sort.collect do |name|
|
10
|
-
"#{name}: #{self
|
10
|
+
"#{name}: #{self.send(:"#{name}").inspect}"
|
11
11
|
end.join(", ")
|
12
12
|
"#<#{self.class} #{attributes_as_nice_string}>"
|
13
13
|
end
|
@@ -10,14 +10,14 @@ module MongoMapper
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def decrement(*args)
|
13
|
-
criteria, keys = criteria_and_keys_from_args(args)
|
13
|
+
criteria, keys, options = criteria_and_keys_from_args(args)
|
14
14
|
values, to_decrement = keys.values, {}
|
15
15
|
keys.keys.each_with_index { |k, i| to_decrement[k] = -values[i].abs }
|
16
16
|
collection.update(criteria, {'$inc' => to_decrement}, :multi => true)
|
17
17
|
end
|
18
18
|
|
19
19
|
def set(*args)
|
20
|
-
criteria, updates = criteria_and_keys_from_args(args)
|
20
|
+
criteria, updates, options = criteria_and_keys_from_args(args)
|
21
21
|
updates.each do |key, value|
|
22
22
|
updates[key] = keys[key.to_s].set(value) if key?(key)
|
23
23
|
end
|
@@ -64,14 +64,26 @@ module MongoMapper
|
|
64
64
|
|
65
65
|
private
|
66
66
|
def modifier_update(modifier, args)
|
67
|
-
criteria, updates = criteria_and_keys_from_args(args)
|
68
|
-
|
67
|
+
criteria, updates, options = criteria_and_keys_from_args(args)
|
68
|
+
if options
|
69
|
+
collection.update(criteria, {modifier => updates}, options.merge(:multi => true))
|
70
|
+
else
|
71
|
+
collection.update(criteria, {modifier => updates}, :multi => true)
|
72
|
+
end
|
69
73
|
end
|
70
74
|
|
71
75
|
def criteria_and_keys_from_args(args)
|
72
|
-
|
73
|
-
|
74
|
-
|
76
|
+
if args[0].is_a?(Hash)
|
77
|
+
criteria = args[0]
|
78
|
+
updates = args[1]
|
79
|
+
options = args[2]
|
80
|
+
else
|
81
|
+
split_args = args.partition{|a| a.is_a?(BSON::ObjectId)}
|
82
|
+
criteria = {:id => split_args[0]}
|
83
|
+
updates = split_args[1].first
|
84
|
+
options = split_args[1].last
|
85
|
+
end
|
86
|
+
[criteria_hash(criteria).to_hash, updates, options]
|
75
87
|
end
|
76
88
|
end
|
77
89
|
|
@@ -79,41 +91,41 @@ module MongoMapper
|
|
79
91
|
self.class.unset(id, *keys)
|
80
92
|
end
|
81
93
|
|
82
|
-
def increment(hash)
|
83
|
-
self.class.increment(id, hash)
|
94
|
+
def increment(hash, options=nil)
|
95
|
+
self.class.increment(id, hash, options)
|
84
96
|
end
|
85
97
|
|
86
|
-
def decrement(hash)
|
87
|
-
self.class.decrement(id, hash)
|
98
|
+
def decrement(hash, options=nil)
|
99
|
+
self.class.decrement(id, hash, options)
|
88
100
|
end
|
89
101
|
|
90
|
-
def set(hash)
|
91
|
-
self.class.set(id, hash)
|
102
|
+
def set(hash, options=nil)
|
103
|
+
self.class.set(id, hash, options)
|
92
104
|
end
|
93
105
|
|
94
|
-
def push(hash)
|
95
|
-
self.class.push(id, hash)
|
106
|
+
def push(hash, options=nil)
|
107
|
+
self.class.push(id, hash, options)
|
96
108
|
end
|
97
109
|
|
98
|
-
def push_all(hash)
|
99
|
-
self.class.push_all(id, hash)
|
110
|
+
def push_all(hash, options=nil)
|
111
|
+
self.class.push_all(id, hash, options)
|
100
112
|
end
|
101
113
|
|
102
|
-
def pull(hash)
|
103
|
-
self.class.pull(id, hash)
|
114
|
+
def pull(hash, options=nil)
|
115
|
+
self.class.pull(id, hash, options)
|
104
116
|
end
|
105
117
|
|
106
|
-
def pull_all(hash)
|
107
|
-
self.class.pull_all(id, hash)
|
118
|
+
def pull_all(hash, options=nil)
|
119
|
+
self.class.pull_all(id, hash, options)
|
108
120
|
end
|
109
121
|
|
110
|
-
def add_to_set(hash)
|
111
|
-
self.class.push_uniq(id, hash)
|
122
|
+
def add_to_set(hash, options=nil)
|
123
|
+
self.class.push_uniq(id, hash, options)
|
112
124
|
end
|
113
125
|
alias push_uniq add_to_set
|
114
126
|
|
115
|
-
def pop(hash)
|
116
|
-
self.class.pop(id, hash)
|
127
|
+
def pop(hash, options=nil)
|
128
|
+
self.class.pop(id, hash, options)
|
117
129
|
end
|
118
130
|
end
|
119
131
|
end
|
@@ -8,8 +8,11 @@ module MongoMapper
|
|
8
8
|
extend ActiveSupport::Concern
|
9
9
|
|
10
10
|
module ClassMethods
|
11
|
+
extend Forwardable
|
11
12
|
include PluckyMethods
|
12
13
|
|
14
|
+
def_delegators :query, :to_a, :size, :empty?
|
15
|
+
|
13
16
|
def find_each(opts={})
|
14
17
|
super(opts).each { |doc| yield(doc) }
|
15
18
|
end
|
@@ -81,7 +84,7 @@ module MongoMapper
|
|
81
84
|
|
82
85
|
def find_some(ids, options={})
|
83
86
|
query = query(options).amend(:_id => ids.flatten.compact.uniq)
|
84
|
-
|
87
|
+
query.all
|
85
88
|
end
|
86
89
|
|
87
90
|
def find_some!(ids, options={})
|
@@ -95,16 +98,6 @@ module MongoMapper
|
|
95
98
|
docs
|
96
99
|
end
|
97
100
|
|
98
|
-
# All query methods that load documents pass through find_one or find_many
|
99
|
-
def find_one(options={})
|
100
|
-
query(options).first
|
101
|
-
end
|
102
|
-
|
103
|
-
# All query methods that load documents pass through find_one or find_many
|
104
|
-
def find_many(options)
|
105
|
-
query(options).all
|
106
|
-
end
|
107
|
-
|
108
101
|
def initialize_each(*docs)
|
109
102
|
instances = []
|
110
103
|
docs = [{}] if docs.blank?
|
@@ -6,9 +6,15 @@ module MongoMapper
|
|
6
6
|
module Querying
|
7
7
|
module PluckyMethods
|
8
8
|
extend Forwardable
|
9
|
-
def_delegators :query, :where, :
|
10
|
-
:
|
11
|
-
:
|
9
|
+
def_delegators :query, :where, :filter,
|
10
|
+
:fields, :ignore, :only,
|
11
|
+
:limit, :paginate, :per_page, :skip, :offset,
|
12
|
+
:sort, :order, :reverse,
|
13
|
+
:count,
|
14
|
+
:distinct,
|
15
|
+
:last, :first, :find_one, :all, :find_each,
|
16
|
+
:find, :find!,
|
17
|
+
:exists?, :exist?
|
12
18
|
end
|
13
19
|
end
|
14
20
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Touch
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def touch(key = :updated_at)
|
7
|
+
raise ArgumentError, "Invalid key named #{key}" unless self.key_names.include?(key.to_s)
|
8
|
+
if self.class.embeddable?
|
9
|
+
self.write_attribute(key, Time.now.utc)
|
10
|
+
self._parent_document.touch
|
11
|
+
else
|
12
|
+
self.set(key => Time.now.utc)
|
13
|
+
end
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/mongo_mapper/version.rb
CHANGED
@@ -393,6 +393,49 @@ class ManyDocumentsProxyTest < Test::Unit::TestCase
|
|
393
393
|
|
394
394
|
project.statuses.count(:name => 'Foo').should == 1
|
395
395
|
end
|
396
|
+
|
397
|
+
should "ignore unpersisted documents" do
|
398
|
+
project = Project.create
|
399
|
+
project.statuses.build(:name => 'Foo')
|
400
|
+
project.statuses.count.should == 0
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
context "size" do
|
405
|
+
should "reflect both persisted and new documents" do
|
406
|
+
project = Project.create
|
407
|
+
3.times { project.statuses.create(:name => 'Foo!') }
|
408
|
+
2.times { project.statuses.build(:name => 'Foo!') }
|
409
|
+
project.statuses.size.should == 5
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
context "empty?" do
|
414
|
+
should "be true with no associated docs" do
|
415
|
+
project = Project.create
|
416
|
+
project.statuses.empty?.should be_true
|
417
|
+
end
|
418
|
+
|
419
|
+
should "be false if a document is built" do
|
420
|
+
project = Project.create
|
421
|
+
project.statuses.build(:name => 'Foo!')
|
422
|
+
project.statuses.empty?.should be_false
|
423
|
+
end
|
424
|
+
|
425
|
+
should "be false if a document is created" do
|
426
|
+
project = Project.create
|
427
|
+
project.statuses.create(:name => 'Foo!')
|
428
|
+
project.statuses.empty?.should be_false
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
context "to_a" do
|
433
|
+
should "include persisted and new documents" do
|
434
|
+
project = Project.create
|
435
|
+
3.times { project.statuses.create(:name => 'Foo!') }
|
436
|
+
2.times { project.statuses.build(:name => 'Foo!') }
|
437
|
+
project.statuses.to_a.size.should == 5
|
438
|
+
end
|
396
439
|
end
|
397
440
|
|
398
441
|
context "to_json" do
|
@@ -801,4 +844,23 @@ class ManyDocumentsProxyTest < Test::Unit::TestCase
|
|
801
844
|
article.paper_id.should == @paper.id
|
802
845
|
end
|
803
846
|
end
|
847
|
+
|
848
|
+
context "criteria" do
|
849
|
+
setup do
|
850
|
+
News::Paper.many :articles, :class_name => 'News::Article'
|
851
|
+
News::Article.belongs_to :paper, :class_name => 'News::Paper'
|
852
|
+
|
853
|
+
@paper = News::Paper.create
|
854
|
+
end
|
855
|
+
|
856
|
+
should "should find associated instances by an object ID" do
|
857
|
+
article = News::Article.create(:paper_id => @paper.id)
|
858
|
+
@paper.articles.should include(article)
|
859
|
+
end
|
860
|
+
|
861
|
+
should "should find associated instances by a string" do
|
862
|
+
article = News::Article.create(:paper_id => @paper.id.to_s)
|
863
|
+
@paper.articles.should include(article)
|
864
|
+
end
|
865
|
+
end
|
804
866
|
end
|
@@ -31,298 +31,323 @@ class ModifierTest < Test::Unit::TestCase
|
|
31
31
|
@page = @page_class.create(:title => 'Home', :tags => %w(foo bar))
|
32
32
|
@page2 = @page_class.create(:title => 'Home')
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
should "work with criteria and keys" do
|
36
36
|
@page_class.unset({:title => 'Home'}, :title, :tags)
|
37
37
|
assert_keys_removed @page, :title, :tags
|
38
38
|
assert_keys_removed @page2, :title, :tags
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
should "work with ids and keys" do
|
42
42
|
@page_class.unset(@page.id, @page2.id, :title, :tags)
|
43
43
|
assert_keys_removed @page, :title, :tags
|
44
44
|
assert_keys_removed @page2, :title, :tags
|
45
45
|
end
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
context "increment" do
|
49
49
|
setup do
|
50
50
|
@page = @page_class.create(:title => 'Home')
|
51
51
|
@page2 = @page_class.create(:title => 'Home')
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
should "work with criteria and modifier hashes" do
|
55
55
|
@page_class.increment({:title => 'Home'}, :day_count => 1, :week_count => 2, :month_count => 3)
|
56
|
-
|
56
|
+
|
57
57
|
assert_page_counts @page, 1, 2, 3
|
58
58
|
assert_page_counts @page2, 1, 2, 3
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
should "work with ids and modifier hash" do
|
62
62
|
@page_class.increment(@page.id, @page2.id, :day_count => 1, :week_count => 2, :month_count => 3)
|
63
|
-
|
63
|
+
|
64
64
|
assert_page_counts @page, 1, 2, 3
|
65
65
|
assert_page_counts @page2, 1, 2, 3
|
66
66
|
end
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
context "decrement" do
|
70
70
|
setup do
|
71
71
|
@page = @page_class.create(:title => 'Home', :day_count => 1, :week_count => 2, :month_count => 3)
|
72
72
|
@page2 = @page_class.create(:title => 'Home', :day_count => 1, :week_count => 2, :month_count => 3)
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
should "work with criteria and modifier hashes" do
|
76
76
|
@page_class.decrement({:title => 'Home'}, :day_count => 1, :week_count => 2, :month_count => 3)
|
77
|
-
|
77
|
+
|
78
78
|
assert_page_counts @page, 0, 0, 0
|
79
79
|
assert_page_counts @page2, 0, 0, 0
|
80
80
|
end
|
81
|
-
|
81
|
+
|
82
82
|
should "work with ids and modifier hash" do
|
83
83
|
@page_class.decrement(@page.id, @page2.id, :day_count => 1, :week_count => 2, :month_count => 3)
|
84
|
-
|
84
|
+
|
85
85
|
assert_page_counts @page, 0, 0, 0
|
86
86
|
assert_page_counts @page2, 0, 0, 0
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
should "decrement with positive or negative numbers" do
|
90
90
|
@page_class.decrement(@page.id, @page2.id, :day_count => -1, :week_count => 2, :month_count => -3)
|
91
|
-
|
91
|
+
|
92
92
|
assert_page_counts @page, 0, 0, 0
|
93
93
|
assert_page_counts @page2, 0, 0, 0
|
94
94
|
end
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
context "set" do
|
98
98
|
setup do
|
99
99
|
@page = @page_class.create(:title => 'Home')
|
100
100
|
@page2 = @page_class.create(:title => 'Home')
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
should "work with criteria and modifier hashes" do
|
104
104
|
@page_class.set({:title => 'Home'}, :title => 'Home Revised')
|
105
|
-
|
105
|
+
|
106
106
|
@page.reload
|
107
107
|
@page.title.should == 'Home Revised'
|
108
|
-
|
108
|
+
|
109
109
|
@page2.reload
|
110
110
|
@page2.title.should == 'Home Revised'
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
should "work with ids and modifier hash" do
|
114
114
|
@page_class.set(@page.id, @page2.id, :title => 'Home Revised')
|
115
|
-
|
115
|
+
|
116
116
|
@page.reload
|
117
117
|
@page.title.should == 'Home Revised'
|
118
|
-
|
118
|
+
|
119
119
|
@page2.reload
|
120
120
|
@page2.title.should == 'Home Revised'
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
should "typecast values before querying" do
|
124
124
|
@page_class.key :tags, Set
|
125
|
-
|
125
|
+
|
126
126
|
assert_nothing_raised do
|
127
127
|
@page_class.set(@page.id, :tags => ['foo', 'bar'].to_set)
|
128
128
|
@page.reload
|
129
129
|
@page.tags.should == Set.new(['foo', 'bar'])
|
130
130
|
end
|
131
131
|
end
|
132
|
-
|
132
|
+
|
133
133
|
should "not typecast keys that are not defined in document" do
|
134
134
|
assert_raises(BSON::InvalidDocument) do
|
135
135
|
@page_class.set(@page.id, :colors => ['red', 'green'].to_set)
|
136
136
|
end
|
137
137
|
end
|
138
|
-
|
138
|
+
|
139
139
|
should "set keys that are not defined in document" do
|
140
140
|
@page_class.set(@page.id, :colors => %w[red green])
|
141
141
|
@page.reload
|
142
142
|
@page[:colors].should == %w[red green]
|
143
143
|
end
|
144
144
|
end
|
145
|
-
|
145
|
+
|
146
146
|
context "push" do
|
147
147
|
setup do
|
148
148
|
@page = @page_class.create(:title => 'Home')
|
149
149
|
@page2 = @page_class.create(:title => 'Home')
|
150
150
|
end
|
151
|
-
|
151
|
+
|
152
152
|
should "work with criteria and modifier hashes" do
|
153
153
|
@page_class.push({:title => 'Home'}, :tags => 'foo')
|
154
|
-
|
154
|
+
|
155
155
|
@page.reload
|
156
156
|
@page.tags.should == %w(foo)
|
157
|
-
|
157
|
+
|
158
158
|
@page2.reload
|
159
159
|
@page2.tags.should == %w(foo)
|
160
160
|
end
|
161
|
-
|
161
|
+
|
162
162
|
should "work with ids and modifier hash" do
|
163
163
|
@page_class.push(@page.id, @page2.id, :tags => 'foo')
|
164
|
-
|
164
|
+
|
165
165
|
@page.reload
|
166
166
|
@page.tags.should == %w(foo)
|
167
|
-
|
167
|
+
|
168
168
|
@page2.reload
|
169
169
|
@page2.tags.should == %w(foo)
|
170
170
|
end
|
171
171
|
end
|
172
|
-
|
172
|
+
|
173
173
|
context "push_all" do
|
174
174
|
setup do
|
175
175
|
@page = @page_class.create(:title => 'Home')
|
176
176
|
@page2 = @page_class.create(:title => 'Home')
|
177
177
|
@tags = %w(foo bar)
|
178
178
|
end
|
179
|
-
|
179
|
+
|
180
180
|
should "work with criteria and modifier hashes" do
|
181
181
|
@page_class.push_all({:title => 'Home'}, :tags => @tags)
|
182
|
-
|
182
|
+
|
183
183
|
@page.reload
|
184
184
|
@page.tags.should == @tags
|
185
|
-
|
185
|
+
|
186
186
|
@page2.reload
|
187
187
|
@page2.tags.should == @tags
|
188
188
|
end
|
189
|
-
|
189
|
+
|
190
190
|
should "work with ids and modifier hash" do
|
191
191
|
@page_class.push_all(@page.id, @page2.id, :tags => @tags)
|
192
|
-
|
192
|
+
|
193
193
|
@page.reload
|
194
194
|
@page.tags.should == @tags
|
195
|
-
|
195
|
+
|
196
196
|
@page2.reload
|
197
197
|
@page2.tags.should == @tags
|
198
198
|
end
|
199
199
|
end
|
200
|
-
|
200
|
+
|
201
201
|
context "pull" do
|
202
202
|
setup do
|
203
203
|
@page = @page_class.create(:title => 'Home', :tags => %w(foo bar))
|
204
204
|
@page2 = @page_class.create(:title => 'Home', :tags => %w(foo bar))
|
205
205
|
end
|
206
|
-
|
206
|
+
|
207
207
|
should "work with criteria and modifier hashes" do
|
208
208
|
@page_class.pull({:title => 'Home'}, :tags => 'foo')
|
209
|
-
|
209
|
+
|
210
210
|
@page.reload
|
211
211
|
@page.tags.should == %w(bar)
|
212
|
-
|
212
|
+
|
213
213
|
@page2.reload
|
214
214
|
@page2.tags.should == %w(bar)
|
215
215
|
end
|
216
|
-
|
216
|
+
|
217
217
|
should "be able to pull with ids and modifier hash" do
|
218
218
|
@page_class.pull(@page.id, @page2.id, :tags => 'foo')
|
219
|
-
|
219
|
+
|
220
220
|
@page.reload
|
221
221
|
@page.tags.should == %w(bar)
|
222
|
-
|
222
|
+
|
223
223
|
@page2.reload
|
224
224
|
@page2.tags.should == %w(bar)
|
225
225
|
end
|
226
226
|
end
|
227
|
-
|
227
|
+
|
228
228
|
context "pull_all" do
|
229
229
|
setup do
|
230
230
|
@page = @page_class.create(:title => 'Home', :tags => %w(foo bar baz))
|
231
231
|
@page2 = @page_class.create(:title => 'Home', :tags => %w(foo bar baz))
|
232
232
|
end
|
233
|
-
|
233
|
+
|
234
234
|
should "work with criteria and modifier hashes" do
|
235
235
|
@page_class.pull_all({:title => 'Home'}, :tags => %w(foo bar))
|
236
|
-
|
236
|
+
|
237
237
|
@page.reload
|
238
238
|
@page.tags.should == %w(baz)
|
239
|
-
|
239
|
+
|
240
240
|
@page2.reload
|
241
241
|
@page2.tags.should == %w(baz)
|
242
242
|
end
|
243
|
-
|
243
|
+
|
244
244
|
should "work with ids and modifier hash" do
|
245
245
|
@page_class.pull_all(@page.id, @page2.id, :tags => %w(foo bar))
|
246
|
-
|
246
|
+
|
247
247
|
@page.reload
|
248
248
|
@page.tags.should == %w(baz)
|
249
|
-
|
249
|
+
|
250
250
|
@page2.reload
|
251
251
|
@page2.tags.should == %w(baz)
|
252
252
|
end
|
253
253
|
end
|
254
|
-
|
254
|
+
|
255
255
|
context "add_to_set" do
|
256
256
|
setup do
|
257
257
|
@page = @page_class.create(:title => 'Home', :tags => 'foo')
|
258
258
|
@page2 = @page_class.create(:title => 'Home')
|
259
259
|
end
|
260
|
-
|
260
|
+
|
261
261
|
should "be able to add to set with criteria and modifier hash" do
|
262
262
|
@page_class.add_to_set({:title => 'Home'}, :tags => 'foo')
|
263
|
-
|
263
|
+
|
264
264
|
@page.reload
|
265
265
|
@page.tags.should == %w(foo)
|
266
|
-
|
266
|
+
|
267
267
|
@page2.reload
|
268
268
|
@page2.tags.should == %w(foo)
|
269
269
|
end
|
270
|
-
|
270
|
+
|
271
271
|
should "be able to add to set with ids and modifier hash" do
|
272
272
|
@page_class.add_to_set(@page.id, @page2.id, :tags => 'foo')
|
273
|
-
|
273
|
+
|
274
274
|
@page.reload
|
275
275
|
@page.tags.should == %w(foo)
|
276
|
-
|
276
|
+
|
277
277
|
@page2.reload
|
278
278
|
@page2.tags.should == %w(foo)
|
279
279
|
end
|
280
280
|
end
|
281
|
-
|
281
|
+
|
282
282
|
context "push_uniq" do
|
283
283
|
setup do
|
284
284
|
@page = @page_class.create(:title => 'Home', :tags => 'foo')
|
285
285
|
@page2 = @page_class.create(:title => 'Home')
|
286
286
|
end
|
287
|
-
|
287
|
+
|
288
288
|
should "be able to push uniq with criteria and modifier hash" do
|
289
289
|
@page_class.push_uniq({:title => 'Home'}, :tags => 'foo')
|
290
|
-
|
290
|
+
|
291
291
|
@page.reload
|
292
292
|
@page.tags.should == %w(foo)
|
293
|
-
|
293
|
+
|
294
294
|
@page2.reload
|
295
295
|
@page2.tags.should == %w(foo)
|
296
296
|
end
|
297
|
-
|
297
|
+
|
298
298
|
should "be able to push uniq with ids and modifier hash" do
|
299
299
|
@page_class.push_uniq(@page.id, @page2.id, :tags => 'foo')
|
300
|
-
|
300
|
+
|
301
301
|
@page.reload
|
302
302
|
@page.tags.should == %w(foo)
|
303
|
-
|
303
|
+
|
304
304
|
@page2.reload
|
305
305
|
@page2.tags.should == %w(foo)
|
306
306
|
end
|
307
307
|
end
|
308
|
-
|
308
|
+
|
309
309
|
context "pop" do
|
310
310
|
setup do
|
311
311
|
@page = @page_class.create(:title => 'Home', :tags => %w(foo bar))
|
312
312
|
end
|
313
|
-
|
313
|
+
|
314
314
|
should "be able to remove the last element the array" do
|
315
315
|
@page_class.pop(@page.id, :tags => 1)
|
316
316
|
@page.reload
|
317
317
|
@page.tags.should == %w(foo)
|
318
318
|
end
|
319
|
-
|
319
|
+
|
320
320
|
should "be able to remove the first element of the array" do
|
321
321
|
@page_class.pop(@page.id, :tags => -1)
|
322
322
|
@page.reload
|
323
323
|
@page.tags.should == %w(bar)
|
324
324
|
end
|
325
325
|
end
|
326
|
+
|
327
|
+
context "additional options (upsert & safe)" do
|
328
|
+
should "be able to pass upsert option" do
|
329
|
+
new_key_value = DateTime.now.to_s
|
330
|
+
@page_class.increment({:title => new_key_value}, {:day_count => 1}, {:upsert => true})
|
331
|
+
@page_class.count(:title => new_key_value).should == 1
|
332
|
+
@page_class.first(:title => new_key_value).day_count.should == 1
|
333
|
+
end
|
334
|
+
|
335
|
+
should "be able to pass safe option" do
|
336
|
+
@page_class.create(:title => "Better Be Safe than Sorry")
|
337
|
+
|
338
|
+
# We are trying to increment a key of type string here which should fail
|
339
|
+
assert_raises(Mongo::OperationFailure) do
|
340
|
+
@page_class.increment({:title => "Better Be Safe than Sorry"}, {:title => 1}, {:safe => true})
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
should "be able to pass both safe and upsert options" do
|
345
|
+
new_key_value = DateTime.now.to_s
|
346
|
+
@page_class.increment({:title => new_key_value}, {:day_count => 1}, {:upsert => true, :safe => true})
|
347
|
+
@page_class.count(:title => new_key_value).should == 1
|
348
|
+
@page_class.first(:title => new_key_value).day_count.should == 1
|
349
|
+
end
|
350
|
+
end
|
326
351
|
end
|
327
352
|
|
328
353
|
context "instance methods" do
|
@@ -331,102 +356,128 @@ class ModifierTest < Test::Unit::TestCase
|
|
331
356
|
page.unset(:title, :tags)
|
332
357
|
assert_keys_removed page, :title, :tags
|
333
358
|
end
|
334
|
-
|
359
|
+
|
335
360
|
should "be able to increment with modifier hashes" do
|
336
361
|
page = @page_class.create
|
337
362
|
page.increment(:day_count => 1, :week_count => 2, :month_count => 3)
|
338
|
-
|
363
|
+
|
339
364
|
assert_page_counts page, 1, 2, 3
|
340
365
|
end
|
341
|
-
|
366
|
+
|
342
367
|
should "be able to decrement with modifier hashes" do
|
343
368
|
page = @page_class.create(:day_count => 1, :week_count => 2, :month_count => 3)
|
344
369
|
page.decrement(:day_count => 1, :week_count => 2, :month_count => 3)
|
345
|
-
|
370
|
+
|
346
371
|
assert_page_counts page, 0, 0, 0
|
347
372
|
end
|
348
|
-
|
373
|
+
|
349
374
|
should "always decrement when decrement is called whether number is positive or negative" do
|
350
375
|
page = @page_class.create(:day_count => 1, :week_count => 2, :month_count => 3)
|
351
376
|
page.decrement(:day_count => -1, :week_count => 2, :month_count => -3)
|
352
|
-
|
377
|
+
|
353
378
|
assert_page_counts page, 0, 0, 0
|
354
379
|
end
|
355
|
-
|
380
|
+
|
356
381
|
should "be able to set with modifier hashes" do
|
357
382
|
page = @page_class.create(:title => 'Home')
|
358
383
|
page.set(:title => 'Home Revised')
|
359
|
-
|
384
|
+
|
360
385
|
page.reload
|
361
386
|
page.title.should == 'Home Revised'
|
362
387
|
end
|
363
|
-
|
388
|
+
|
364
389
|
should "be able to push with modifier hashes" do
|
365
390
|
page = @page_class.create
|
366
391
|
page.push(:tags => 'foo')
|
367
|
-
|
392
|
+
|
368
393
|
page.reload
|
369
394
|
page.tags.should == %w(foo)
|
370
395
|
end
|
371
|
-
|
396
|
+
|
372
397
|
should "be able to push_all with modifier hashes" do
|
373
398
|
page = @page_class.create
|
374
399
|
page.push_all(:tags => %w(foo bar))
|
375
|
-
|
400
|
+
|
376
401
|
page.reload
|
377
402
|
page.tags.should == %w(foo bar)
|
378
403
|
end
|
379
|
-
|
404
|
+
|
380
405
|
should "be able to pull with criteria and modifier hashes" do
|
381
406
|
page = @page_class.create(:tags => %w(foo bar))
|
382
407
|
page.pull(:tags => 'foo')
|
383
|
-
|
408
|
+
|
384
409
|
page.reload
|
385
410
|
page.tags.should == %w(bar)
|
386
411
|
end
|
387
|
-
|
412
|
+
|
388
413
|
should "be able to pull_all with criteria and modifier hashes" do
|
389
414
|
page = @page_class.create(:tags => %w(foo bar baz))
|
390
415
|
page.pull_all(:tags => %w(foo bar))
|
391
|
-
|
416
|
+
|
392
417
|
page.reload
|
393
418
|
page.tags.should == %w(baz)
|
394
419
|
end
|
395
|
-
|
420
|
+
|
396
421
|
should "be able to add_to_set with criteria and modifier hash" do
|
397
422
|
page = @page_class.create(:tags => 'foo')
|
398
423
|
page2 = @page_class.create
|
399
|
-
|
424
|
+
|
400
425
|
page.add_to_set(:tags => 'foo')
|
401
426
|
page2.add_to_set(:tags => 'foo')
|
402
|
-
|
427
|
+
|
403
428
|
page.reload
|
404
429
|
page.tags.should == %w(foo)
|
405
|
-
|
430
|
+
|
406
431
|
page2.reload
|
407
432
|
page2.tags.should == %w(foo)
|
408
433
|
end
|
409
|
-
|
434
|
+
|
410
435
|
should "be able to push uniq with criteria and modifier hash" do
|
411
436
|
page = @page_class.create(:tags => 'foo')
|
412
437
|
page2 = @page_class.create
|
413
|
-
|
438
|
+
|
414
439
|
page.push_uniq(:tags => 'foo')
|
415
440
|
page2.push_uniq(:tags => 'foo')
|
416
|
-
|
441
|
+
|
417
442
|
page.reload
|
418
443
|
page.tags.should == %w(foo)
|
419
|
-
|
444
|
+
|
420
445
|
page2.reload
|
421
446
|
page2.tags.should == %w(foo)
|
422
447
|
end
|
423
|
-
|
448
|
+
|
424
449
|
should "be able to pop with modifier hashes" do
|
425
450
|
page = @page_class.create(:tags => %w(foo bar))
|
426
451
|
page.pop(:tags => 1)
|
427
|
-
|
452
|
+
|
428
453
|
page.reload
|
429
454
|
page.tags.should == %w(foo)
|
430
455
|
end
|
456
|
+
|
457
|
+
should "be able to pass upsert option" do
|
458
|
+
page = @page_class.create(:title => "Upsert Page")
|
459
|
+
page.increment({:new_count => 1}, {:upsert => true})
|
460
|
+
|
461
|
+
page.reload
|
462
|
+
page.new_count.should == 1
|
463
|
+
end
|
464
|
+
|
465
|
+
should "be able to pass safe option" do
|
466
|
+
page = @page_class.create(:title => "Safe Page")
|
467
|
+
|
468
|
+
# We are trying to increment a key of type string here which should fail
|
469
|
+
assert_raises(Mongo::OperationFailure) do
|
470
|
+
page.increment({:title => 1}, {:safe => true})
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
should "be able to pass upsert and safe options" do
|
475
|
+
page = @page_class.create(:title => "Upsert and Safe Page")
|
476
|
+
page.increment({:another_count => 1}, {:upsert => true, :safe => true})
|
477
|
+
|
478
|
+
page.reload
|
479
|
+
page.another_count.should == 1
|
480
|
+
end
|
481
|
+
|
431
482
|
end
|
432
483
|
end
|