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.
@@ -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
@@ -22,6 +22,7 @@ module MongoMapper
22
22
  include Plugins::Timestamps
23
23
  include Plugins::Validations
24
24
  include Plugins::EmbeddedCallbacks
25
+ include Plugins::Touch
25
26
 
26
27
  included do
27
28
  extend Plugins
@@ -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
- # strip milliseconds as Ruby does micro and bson does milli and rounding rounded wrong
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
@@ -4,6 +4,7 @@ module MongoMapper
4
4
  module Associations
5
5
  class SingleAssociation < Base
6
6
  def setup(model)
7
+ @model = model
7
8
  model.associations_module.module_eval <<-end_eval
8
9
  def #{name}
9
10
  proxy = get_proxy(associations[#{name.inspect}])
@@ -7,6 +7,10 @@ module MongoMapper
7
7
  def destroy
8
8
  run_callbacks(:destroy) { super }
9
9
  end
10
+
11
+ def touch(*)
12
+ run_callbacks(:touch) { super }
13
+ end
10
14
 
11
15
  private
12
16
  def create_or_update(*)
@@ -8,6 +8,7 @@ module MongoMapper
8
8
  extend ::ActiveModel::Callbacks
9
9
 
10
10
  define_model_callbacks :save, :create, :update, :destroy, :only => [:before, :after]
11
+ define_model_callbacks :touch, :only => [:after]
11
12
  end
12
13
 
13
14
  def run_callbacks(callback, *args, &block)
@@ -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[name].inspect}"
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
- collection.update(criteria, {modifier => updates}, :multi => true)
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
- keys = args.pop
73
- criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
74
- [criteria_hash(criteria).to_hash, keys]
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
- find_many(query.to_hash).compact
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, :fields, :limit, :skip, :sort,
10
- :count, :last, :first, :all, :paginate,
11
- :find, :find!, :exists?, :exist?, :find_each
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
@@ -1,4 +1,4 @@
1
1
  # encoding: UTF-8
2
2
  module MongoMapper
3
- Version = '0.11.0'
3
+ Version = '0.11.1'
4
4
  end
@@ -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