mongo_mapper 0.7.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -317,6 +317,14 @@ class ModifierTest < Test::Unit::TestCase
317
317
  page2.reload
318
318
  page.tags.should == %w(foo)
319
319
  end
320
- end
320
+
321
+ should "be able to pop with modifier hashes" do
322
+ page = @page_class.create(:tags => %w(foo bar))
323
+
324
+ page.pop({:tags => 1})
321
325
 
326
+ page.reload
327
+ page.tags.should == %w(foo)
328
+ end
329
+ end
322
330
  end
@@ -1,19 +1,19 @@
1
1
  require 'test_helper'
2
2
 
3
- class ValidationsTest < Test::Unit::TestCase
3
+ class ValidationsTest < Test::Unit::TestCase
4
4
  context "Saving a new document that is invalid" do
5
5
  setup do
6
6
  @document = Doc do
7
7
  key :name, String, :required => true
8
8
  end
9
9
  end
10
-
10
+
11
11
  should "not insert document" do
12
12
  doc = @document.new
13
13
  doc.save
14
14
  @document.count.should == 0
15
15
  end
16
-
16
+
17
17
  should "populate document's errors" do
18
18
  doc = @document.new
19
19
  doc.errors.size.should == 0
@@ -28,7 +28,7 @@ class ValidationsTest < Test::Unit::TestCase
28
28
  key :name, String, :required => true
29
29
  end
30
30
  end
31
-
31
+
32
32
  should "raise error" do
33
33
  doc = @document.new
34
34
  lambda { doc.save! }.should raise_error(MongoMapper::DocumentNotValid)
@@ -41,7 +41,7 @@ class ValidationsTest < Test::Unit::TestCase
41
41
  key :name, String, :required => true
42
42
  end
43
43
  end
44
-
44
+
45
45
  should "raise error" do
46
46
  lambda { @document.create! }.should raise_error(MongoMapper::DocumentNotValid)
47
47
  end
@@ -51,29 +51,29 @@ class ValidationsTest < Test::Unit::TestCase
51
51
  instance.new_record?.should be_false
52
52
  end
53
53
  end
54
-
54
+
55
55
  context "Saving an existing document that is invalid" do
56
56
  setup do
57
57
  @document = Doc do
58
58
  key :name, String, :required => true
59
59
  end
60
-
60
+
61
61
  @doc = @document.create(:name => 'John Nunemaker')
62
62
  end
63
-
63
+
64
64
  should "not update document" do
65
65
  @doc.name = nil
66
66
  @doc.save
67
67
  @doc.reload.name.should == 'John Nunemaker'
68
68
  end
69
-
69
+
70
70
  should "populate document's errors" do
71
71
  @doc.name = nil
72
72
  @doc.save
73
73
  @doc.errors.full_messages.should == ["Name can't be empty"]
74
74
  end
75
75
  end
76
-
76
+
77
77
  context "Adding validation errors" do
78
78
  setup do
79
79
  @document = Doc do
@@ -83,38 +83,38 @@ class ValidationsTest < Test::Unit::TestCase
83
83
  end
84
84
  end
85
85
  end
86
-
86
+
87
87
  should "work with validate_on_create callback" do
88
88
  @document.validate_on_create :action_present
89
-
89
+
90
90
  doc = @document.new
91
91
  doc.action = nil
92
92
  doc.should have_error_on(:action)
93
-
93
+
94
94
  doc.action = 'kick'
95
95
  doc.should_not have_error_on(:action)
96
96
  doc.save
97
-
97
+
98
98
  doc.action = nil
99
99
  doc.should_not have_error_on(:action)
100
100
  end
101
-
101
+
102
102
  should "work with validate_on_update callback" do
103
103
  @document.validate_on_update :action_present
104
-
104
+
105
105
  doc = @document.new
106
106
  doc.action = nil
107
107
  doc.should_not have_error_on(:action)
108
108
  doc.save
109
-
109
+
110
110
  doc.action = nil
111
111
  doc.should have_error_on(:action)
112
-
112
+
113
113
  doc.action = 'kick'
114
114
  doc.should_not have_error_on(:action)
115
115
  end
116
116
  end
117
-
117
+
118
118
  context "validating uniqueness of" do
119
119
  setup do
120
120
  @document = Doc do
@@ -167,13 +167,13 @@ class ValidationsTest < Test::Unit::TestCase
167
167
  doc2 = @document.new("name" => "joe")
168
168
  doc2.should have_error_on(:name)
169
169
  end
170
-
170
+
171
171
  should "allow multiple blank entries if :allow_blank => true" do
172
172
  document = Doc do
173
173
  key :name
174
174
  validates_uniqueness_of :name, :allow_blank => :true
175
175
  end
176
-
176
+
177
177
  doc = document.new("name" => "")
178
178
  doc.save.should be_true
179
179
 
@@ -219,7 +219,7 @@ class ValidationsTest < Test::Unit::TestCase
219
219
  validates_uniqueness_of :name, :case_sensitive => false
220
220
  end
221
221
  end
222
-
222
+
223
223
  should "fail on entries that differ only in case" do
224
224
  doc = @document.new("name" => "BLAMMO")
225
225
  doc.save.should be_true
@@ -232,6 +232,19 @@ class ValidationsTest < Test::Unit::TestCase
232
232
  doc = @document.new("name" => nil)
233
233
  lambda { doc.valid? }.should_not raise_error
234
234
  end
235
+
236
+ should "not raise an error if special Regexp characters used" do
237
+ doc = @document.new("name" => '?')
238
+ lambda { doc.valid? }.should_not raise_error
239
+ end
240
+
241
+ should "check for uniqueness using entire string" do
242
+ doc = @document.new("name" => "John Doe")
243
+ doc.save.should be_true
244
+
245
+ doc2 = @document.new("name" => "John")
246
+ doc2.valid?.should be_true
247
+ end
235
248
  end
236
249
 
237
250
  context "scoped by a single attribute" do
@@ -246,7 +259,7 @@ class ValidationsTest < Test::Unit::TestCase
246
259
  should "fail if the same name exists in the scope" do
247
260
  doc = @document.new("name" => "joe", "scope" => "one")
248
261
  doc.save.should be_true
249
-
262
+
250
263
  @document \
251
264
  .stubs(:first) \
252
265
  .with(:name => 'joe', :scope => "one") \
@@ -279,11 +292,11 @@ class ValidationsTest < Test::Unit::TestCase
279
292
  validates_uniqueness_of :name, :scope => [:first_scope, :second_scope]
280
293
  end
281
294
  end
282
-
295
+
283
296
  should "fail if the same name exists in the scope" do
284
297
  doc = @document.new("name" => "joe", "first_scope" => "one", "second_scope" => "two")
285
298
  doc.save.should be_true
286
-
299
+
287
300
  @document \
288
301
  .stubs(:first) \
289
302
  .with(:name => 'joe', :first_scope => 'one', :second_scope => 'two') \
@@ -292,11 +305,11 @@ class ValidationsTest < Test::Unit::TestCase
292
305
  doc2 = @document.new("name" => "joe", "first_scope" => "one", "second_scope" => "two")
293
306
  doc2.should have_error_on(:name)
294
307
  end
295
-
308
+
296
309
  should "pass if the same name exists in a different scope" do
297
310
  doc = @document.new("name" => "joe", "first_scope" => "one", "second_scope" => "two")
298
311
  doc.save.should be_true
299
-
312
+
300
313
  @document \
301
314
  .stubs(:first) \
302
315
  .with(:name => 'joe', :first_scope => 'one', :second_scope => 'one') \
@@ -307,21 +320,21 @@ class ValidationsTest < Test::Unit::TestCase
307
320
  end
308
321
  end
309
322
  end
310
-
323
+
311
324
  context "validates uniqueness of with :unique shortcut" do
312
325
  should "work" do
313
326
  @document = Doc do
314
327
  key :name, String, :unique => true
315
328
  end
316
-
329
+
317
330
  doc = @document.create(:name => 'John')
318
331
  doc.should_not have_error_on(:name)
319
-
332
+
320
333
  @document \
321
334
  .stubs(:first) \
322
335
  .with(:name => 'John') \
323
336
  .returns(doc)
324
-
337
+
325
338
  second_john = @document.create(:name => 'John')
326
339
  second_john.should have_error_on(:name, 'has already been taken')
327
340
  end
@@ -1,4 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../lib/mongo_mapper')
2
+ require 'fileutils'
2
3
 
3
4
  gem 'jnunemaker-matchy', '0.4.0'
4
5
  gem 'shoulda', '2.10.2'
@@ -105,12 +105,6 @@ class DocumentTest < Test::Unit::TestCase
105
105
  @document.new._id.should be_instance_of(Mongo::ObjectID)
106
106
  end
107
107
 
108
- should "have to_param that is string representation of id" do
109
- doc = @document.new(:id => Mongo::ObjectID.new)
110
- doc.to_param.should == doc.id.to_s
111
- doc.to_param.should be_instance_of(String)
112
- end
113
-
114
108
  should "have access to logger" do
115
109
  doc = @document.new
116
110
  doc.logger.should == @document.logger
@@ -11,7 +11,7 @@ module KeyOverride
11
11
  end
12
12
 
13
13
  class EmbeddedDocumentTest < Test::Unit::TestCase
14
- context "" do
14
+ context "EmbeddedDocuments" do
15
15
  setup do
16
16
  class ::Grandparent
17
17
  include MongoMapper::EmbeddedDocument
@@ -221,12 +221,6 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
221
221
  end
222
222
  end
223
223
 
224
- should "have to_param that is string representation of id" do
225
- doc = @document.new
226
- doc.to_param.should == doc.id.to_s
227
- doc.to_param.should be_instance_of(String)
228
- end
229
-
230
224
  should "have access to class logger" do
231
225
  doc = @document.new
232
226
  doc.logger.should == @document.logger
@@ -3,25 +3,25 @@ require 'models'
3
3
 
4
4
  class QueryTest < Test::Unit::TestCase
5
5
  include MongoMapper
6
-
6
+
7
7
  should "raise error if provided something other than a hash" do
8
8
  lambda { Query.new(Room) }.should raise_error(ArgumentError)
9
9
  lambda { Query.new(Room, 1) }.should raise_error(ArgumentError)
10
10
  end
11
-
11
+
12
12
  should "symbolize the keys of the hash provided" do
13
13
  Query.new(Room, 'offset' => 1).options.keys.map do |key|
14
14
  key.should be_instance_of(Symbol)
15
15
  end
16
16
  end
17
-
17
+
18
18
  context "Converting conditions to criteria" do
19
19
  should "not add _type to query if model does not have superclass that is single collection inherited" do
20
20
  Query.new(Message, :foo => 'bar').criteria.should == {
21
21
  :foo => 'bar'
22
22
  }
23
23
  end
24
-
24
+
25
25
  should "not add _type to nested conditions" do
26
26
  Query.new(Enter, :foo => 'bar', :age => {'$gt' => 21}).criteria.should == {
27
27
  :foo => 'bar',
@@ -29,14 +29,14 @@ class QueryTest < Test::Unit::TestCase
29
29
  :_type => 'Enter'
30
30
  }
31
31
  end
32
-
32
+
33
33
  should "automatically add _type to query if model is single collection inherited" do
34
34
  Query.new(Enter, :foo => 'bar').criteria.should == {
35
35
  :foo => 'bar',
36
36
  :_type => 'Enter'
37
37
  }
38
38
  end
39
-
39
+
40
40
  %w{gt lt gte lte ne in nin mod all size where exists}.each do |operator|
41
41
  next if operator == 'size' && RUBY_VERSION >= '1.9.1' # 1.9 defines Symbol#size
42
42
 
@@ -46,75 +46,75 @@ class QueryTest < Test::Unit::TestCase
46
46
  }
47
47
  end
48
48
  end
49
-
49
+
50
50
  should "normalize value when using symbol operators" do
51
51
  time = Time.now.in_time_zone('Indiana (East)')
52
52
  criteria = Query.new(Room, :created_at.gt => time).criteria
53
53
  criteria[:created_at]['$gt'].should be_utc
54
54
  end
55
-
55
+
56
56
  should "work with simple criteria" do
57
57
  Query.new(Room, :foo => 'bar').criteria.should == {
58
58
  :foo => 'bar'
59
59
  }
60
-
60
+
61
61
  Query.new(Room, :foo => 'bar', :baz => 'wick').criteria.should == {
62
- :foo => 'bar',
62
+ :foo => 'bar',
63
63
  :baz => 'wick'
64
64
  }
65
65
  end
66
-
66
+
67
67
  should "convert id to _id" do
68
68
  id = Mongo::ObjectID.new
69
69
  Query.new(Room, :id => id).criteria.should == {:_id => id}
70
70
  end
71
-
71
+
72
72
  should "convert id with symbol operator to _id with modifier" do
73
73
  id = Mongo::ObjectID.new
74
74
  Query.new(Room, :id.ne => id).criteria.should == {
75
75
  :_id => {'$ne' => id}
76
76
  }
77
77
  end
78
-
78
+
79
79
  should "make sure that _id's are object ids" do
80
80
  id = Mongo::ObjectID.new
81
81
  Query.new(Room, :_id => id.to_s).criteria.should == {:_id => id}
82
82
  end
83
-
83
+
84
84
  should "work fine with _id's that are object ids" do
85
85
  id = Mongo::ObjectID.new
86
86
  Query.new(Room, :_id => id).criteria.should == {:_id => id}
87
87
  end
88
-
88
+
89
89
  should "make sure other object id typed keys get converted" do
90
90
  id = Mongo::ObjectID.new
91
91
  Query.new(Message, :room_id => id.to_s).criteria.should == {:room_id => id}
92
92
  end
93
-
93
+
94
94
  should "work fine with object ids for object id typed keys" do
95
95
  id = Mongo::ObjectID.new
96
96
  Query.new(Message, :room_id => id).criteria.should == {:room_id => id}
97
97
  end
98
-
98
+
99
99
  should "convert times to utc if they aren't already" do
100
100
  time = Time.now.in_time_zone('Indiana (East)')
101
101
  criteria = Query.new(Room, :created_at => time).criteria
102
102
  criteria[:created_at].utc?.should be_true
103
103
  end
104
-
104
+
105
105
  should "not funk with times already in utc" do
106
106
  time = Time.now.utc
107
107
  criteria = Query.new(Room, :created_at => time).criteria
108
108
  criteria[:created_at].utc?.should be_true
109
109
  criteria[:created_at].should == time
110
110
  end
111
-
111
+
112
112
  should "use $in for arrays" do
113
113
  Query.new(Room, :foo => [1,2,3]).criteria.should == {
114
114
  :foo => {'$in' => [1,2,3]}
115
115
  }
116
116
  end
117
-
117
+
118
118
  should "not use $in for arrays if already using array operator" do
119
119
  Query.new(Room, :foo => {'$all' => [1,2,3]}).criteria.should == {
120
120
  :foo => {'$all' => [1,2,3]}
@@ -124,155 +124,179 @@ class QueryTest < Test::Unit::TestCase
124
124
  :foo => {'$any' => [1,2,3]}
125
125
  }
126
126
  end
127
-
127
+
128
+ should "use $in for sets" do
129
+ Query.new(Room, :foo => Set.new([1,2,3])).criteria.should == {
130
+ :foo => {'$in' => [1,2,3]}
131
+ }
132
+ end
133
+
134
+ should "not use $in for sets if already using array operator" do
135
+ Query.new(Room, :foo => {'$all' => Set.new([1,2,3])}).criteria.should == {
136
+ :foo => {'$all' => [1,2,3]}
137
+ }
138
+
139
+ Query.new(Room, :foo => {'$any' => Set.new([1,2,3])}).criteria.should == {
140
+ :foo => {'$any' => [1,2,3]}
141
+ }
142
+ end
143
+
128
144
  should "work arbitrarily deep" do
129
145
  Query.new(Room, :foo => {:bar => [1,2,3]}).criteria.should == {
130
146
  :foo => {:bar => {'$in' => [1,2,3]}}
131
147
  }
132
-
148
+
133
149
  Query.new(Room, :foo => {:bar => {'$any' => [1,2,3]}}).criteria.should == {
134
150
  :foo => {:bar => {'$any' => [1,2,3]}}
135
151
  }
136
152
  end
153
+
154
+ should "make sure that ids in array are object ids" do
155
+ id1, id2, id3 = Mongo::ObjectID.new, Mongo::ObjectID.new, Mongo::ObjectID.new
156
+
157
+ Query.new(Room, :_id => [id1.to_s, id2.to_s, id3.to_s]).criteria.should == {
158
+ :_id => {'$in' => [id1, id2, id3]}
159
+ }
160
+ end
137
161
  end
138
-
162
+
139
163
  context "ordering" do
140
164
  should "single field with ascending direction" do
141
165
  sort = [['foo', 1]]
142
166
  Query.new(Room, :order => 'foo asc').options[:sort].should == sort
143
167
  Query.new(Room, :order => 'foo ASC').options[:sort].should == sort
144
168
  end
145
-
169
+
146
170
  should "single field with descending direction" do
147
171
  sort = [['foo', -1]]
148
172
  Query.new(Room, :order => 'foo desc').options[:sort].should == sort
149
173
  Query.new(Room, :order => 'foo DESC').options[:sort].should == sort
150
174
  end
151
-
175
+
152
176
  should "convert order operators to mongo sort" do
153
177
  Query.new(Room, :order => :foo.asc).options[:sort].should == [['foo', 1]]
154
178
  Query.new(Room, :order => :foo.desc).options[:sort].should == [['foo', -1]]
155
179
  end
156
-
180
+
157
181
  should "convert array of order operators to mongo sort" do
158
182
  Query.new(Room, :order => [:foo.asc, :bar.desc]).options[:sort].should == [['foo', 1], ['bar', -1]]
159
183
  end
160
-
184
+
161
185
  should "convert field without direction to ascending" do
162
186
  sort = [['foo', 1]]
163
187
  Query.new(Room, :order => 'foo').options[:sort].should == sort
164
188
  end
165
-
189
+
166
190
  should "convert multiple fields with directions" do
167
191
  sort = [['foo', -1], ['bar', 1], ['baz', -1]]
168
192
  Query.new(Room, :order => 'foo desc, bar asc, baz desc').options[:sort].should == sort
169
193
  end
170
-
194
+
171
195
  should "convert multiple fields with some missing directions" do
172
196
  sort = [['foo', -1], ['bar', 1], ['baz', 1]]
173
197
  Query.new(Room, :order => 'foo desc, bar, baz').options[:sort].should == sort
174
198
  end
175
-
199
+
176
200
  should "just use sort if sort and order are present" do
177
201
  sort = [['$natural', 1]]
178
202
  Query.new(Room, :sort => sort, :order => 'foo asc').options[:sort].should == sort
179
203
  end
180
-
204
+
181
205
  should "normalize id to _id" do
182
206
  Query.new(Room, :order => :id.asc).options[:sort].should == [['_id', 1]]
183
207
  end
184
-
208
+
185
209
  should "convert natural in order to proper" do
186
210
  sort = [['$natural', 1]]
187
211
  Query.new(Room, :order => '$natural asc').options[:sort].should == sort
188
212
  sort = [['$natural', -1]]
189
213
  Query.new(Room, :order => '$natural desc').options[:sort].should == sort
190
214
  end
191
-
215
+
192
216
  should "work for natural order ascending" do
193
217
  Query.new(Room, :sort => {'$natural' => 1}).options[:sort]['$natural'].should == 1
194
218
  end
195
-
219
+
196
220
  should "work for natural order descending" do
197
221
  Query.new(Room, :sort => {'$natural' => -1}).options[:sort]['$natural'].should == -1
198
222
  end
199
223
  end
200
-
224
+
201
225
  context "skip" do
202
226
  should "default to 0" do
203
227
  Query.new(Room, {}).options[:skip].should == 0
204
228
  end
205
-
229
+
206
230
  should "use skip provided" do
207
231
  Query.new(Room, :skip => 2).options[:skip].should == 2
208
232
  end
209
-
233
+
210
234
  should "covert string to integer" do
211
235
  Query.new(Room, :skip => '2').options[:skip].should == 2
212
236
  end
213
-
237
+
214
238
  should "convert offset to skip" do
215
239
  Query.new(Room, :offset => 1).options[:skip].should == 1
216
240
  end
217
241
  end
218
-
242
+
219
243
  context "limit" do
220
244
  should "default to 0" do
221
245
  Query.new(Room, {}).options[:limit].should == 0
222
246
  end
223
-
247
+
224
248
  should "use limit provided" do
225
249
  Query.new(Room, :limit => 2).options[:limit].should == 2
226
250
  end
227
-
251
+
228
252
  should "covert string to integer" do
229
253
  Query.new(Room, :limit => '2').options[:limit].should == 2
230
254
  end
231
255
  end
232
-
256
+
233
257
  context "fields" do
234
258
  should "default to nil" do
235
259
  Query.new(Room, {}).options[:fields].should be(nil)
236
260
  end
237
-
261
+
238
262
  should "be converted to nil if empty string" do
239
263
  Query.new(Room, :fields => '').options[:fields].should be(nil)
240
264
  end
241
-
265
+
242
266
  should "be converted to nil if []" do
243
267
  Query.new(Room, :fields => []).options[:fields].should be(nil)
244
268
  end
245
-
269
+
246
270
  should "should work with array" do
247
271
  Query.new(Room, {:fields => %w(a b)}).options[:fields].should == %w(a b)
248
272
  end
249
-
273
+
250
274
  should "convert comma separated list to array" do
251
275
  Query.new(Room, {:fields => 'a, b'}).options[:fields].should == %w(a b)
252
276
  end
253
-
277
+
254
278
  should "also work as select" do
255
279
  Query.new(Room, :select => %w(a b)).options[:fields].should == %w(a b)
256
280
  end
257
-
281
+
258
282
  should "also work with select as array of symbols" do
259
283
  Query.new(Room, :select => [:a, :b]).options[:fields].should == [:a, :b]
260
284
  end
261
285
  end
262
-
286
+
263
287
  context "Condition auto-detection" do
264
288
  should "know :conditions are criteria" do
265
289
  finder = Query.new(Room, :conditions => {:foo => 'bar'})
266
290
  finder.criteria.should == {:foo => 'bar'}
267
291
  finder.options.keys.should_not include(:conditions)
268
292
  end
269
-
293
+
270
294
  should "know fields is an option" do
271
295
  finder = Query.new(Room, :fields => ['foo'])
272
296
  finder.options[:fields].should == ['foo']
273
297
  finder.criteria.keys.should_not include(:fields)
274
298
  end
275
-
299
+
276
300
  # select gets converted to fields so just checking keys
277
301
  should "know select is an option" do
278
302
  finder = Query.new(Room, :select => 'foo')
@@ -280,13 +304,13 @@ class QueryTest < Test::Unit::TestCase
280
304
  finder.criteria.keys.should_not include(:select)
281
305
  finder.criteria.keys.should_not include(:fields)
282
306
  end
283
-
307
+
284
308
  should "know skip is an option" do
285
309
  finder = Query.new(Room, :skip => 10)
286
310
  finder.options[:skip].should == 10
287
311
  finder.criteria.keys.should_not include(:skip)
288
312
  end
289
-
313
+
290
314
  # offset gets converted to skip so just checking keys
291
315
  should "know offset is an option" do
292
316
  finder = Query.new(Room, :offset => 10)
@@ -313,7 +337,7 @@ class QueryTest < Test::Unit::TestCase
313
337
  finder.options.keys.should include(:sort)
314
338
  finder.criteria.keys.should_not include(:sort)
315
339
  end
316
-
340
+
317
341
  should "work with full range of things" do
318
342
  query_options = Query.new(Room, {
319
343
  :foo => 'bar',
@@ -323,12 +347,12 @@ class QueryTest < Test::Unit::TestCase
323
347
  :limit => 10,
324
348
  :skip => 10,
325
349
  })
326
-
350
+
327
351
  query_options.criteria.should == {
328
352
  :foo => 'bar',
329
353
  :baz => true,
330
354
  }
331
-
355
+
332
356
  query_options.options.should == {
333
357
  :sort => [['foo', 1]],
334
358
  :fields => ['foo', 'baz'],