crnixon-mongomapper 0.2.0 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. data/.gitignore +1 -0
  2. data/History +48 -0
  3. data/README.rdoc +5 -3
  4. data/Rakefile +6 -4
  5. data/VERSION +1 -1
  6. data/bin/mmconsole +56 -0
  7. data/lib/mongomapper.rb +29 -18
  8. data/lib/mongomapper/associations.rb +53 -38
  9. data/lib/mongomapper/associations/base.rb +53 -20
  10. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +34 -0
  11. data/lib/mongomapper/associations/belongs_to_proxy.rb +10 -14
  12. data/lib/mongomapper/associations/many_documents_as_proxy.rb +27 -0
  13. data/lib/mongomapper/associations/many_documents_proxy.rb +103 -0
  14. data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +33 -0
  15. data/lib/mongomapper/associations/{has_many_embedded_proxy.rb → many_embedded_proxy.rb} +6 -8
  16. data/lib/mongomapper/associations/many_polymorphic_proxy.rb +11 -0
  17. data/lib/mongomapper/associations/{array_proxy.rb → many_proxy.rb} +1 -1
  18. data/lib/mongomapper/associations/proxy.rb +24 -21
  19. data/lib/mongomapper/callbacks.rb +1 -1
  20. data/lib/mongomapper/document.rb +160 -74
  21. data/lib/mongomapper/dynamic_finder.rb +38 -0
  22. data/lib/mongomapper/embedded_document.rb +154 -105
  23. data/lib/mongomapper/finder_options.rb +11 -7
  24. data/lib/mongomapper/key.rb +15 -21
  25. data/lib/mongomapper/pagination.rb +52 -0
  26. data/lib/mongomapper/rails_compatibility/document.rb +15 -0
  27. data/lib/mongomapper/rails_compatibility/embedded_document.rb +25 -0
  28. data/lib/mongomapper/serialization.rb +1 -1
  29. data/lib/mongomapper/serializers/json_serializer.rb +15 -0
  30. data/lib/mongomapper/support.rb +30 -0
  31. data/mongomapper.gemspec +87 -46
  32. data/test/NOTE_ON_TESTING +1 -0
  33. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +53 -0
  34. data/test/functional/associations/test_belongs_to_proxy.rb +45 -0
  35. data/test/functional/associations/test_many_documents_as_proxy.rb +253 -0
  36. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +131 -0
  37. data/test/functional/associations/test_many_embedded_proxy.rb +106 -0
  38. data/test/functional/associations/test_many_polymorphic_proxy.rb +261 -0
  39. data/test/functional/associations/test_many_proxy.rb +295 -0
  40. data/test/functional/test_associations.rb +47 -0
  41. data/test/{test_callbacks.rb → functional/test_callbacks.rb} +2 -1
  42. data/test/functional/test_document.rb +952 -0
  43. data/test/functional/test_pagination.rb +81 -0
  44. data/test/functional/test_rails_compatibility.rb +30 -0
  45. data/test/functional/test_validations.rb +172 -0
  46. data/test/models.rb +169 -0
  47. data/test/test_helper.rb +7 -2
  48. data/test/unit/serializers/test_json_serializer.rb +189 -0
  49. data/test/unit/test_association_base.rb +144 -0
  50. data/test/unit/test_document.rb +123 -0
  51. data/test/unit/test_embedded_document.rb +526 -0
  52. data/test/{test_finder_options.rb → unit/test_finder_options.rb} +36 -1
  53. data/test/{test_key.rb → unit/test_key.rb} +59 -12
  54. data/test/{test_mongomapper.rb → unit/test_mongomapper.rb} +0 -0
  55. data/test/{test_observing.rb → unit/test_observing.rb} +0 -0
  56. data/test/unit/test_pagination.rb +113 -0
  57. data/test/unit/test_rails_compatibility.rb +34 -0
  58. data/test/{test_serializations.rb → unit/test_serializations.rb} +0 -2
  59. data/test/{test_validations.rb → unit/test_validations.rb} +0 -134
  60. metadata +81 -43
  61. data/lib/mongomapper/associations/has_many_proxy.rb +0 -28
  62. data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +0 -31
  63. data/lib/mongomapper/rails_compatibility.rb +0 -23
  64. data/test/serializers/test_json_serializer.rb +0 -104
  65. data/test/test_associations.rb +0 -174
  66. data/test/test_document.rb +0 -944
  67. data/test/test_embedded_document.rb +0 -253
  68. data/test/test_rails_compatibility.rb +0 -29
@@ -28,7 +28,6 @@ class FinderOptionsTest < Test::Unit::TestCase
28
28
  end
29
29
  end
30
30
 
31
-
32
31
  context "Converting conditions to criteria" do
33
32
  should "work with simple criteria" do
34
33
  FinderOptions.to_mongo_criteria(:foo => 'bar').should == {
@@ -47,10 +46,24 @@ class FinderOptionsTest < Test::Unit::TestCase
47
46
  }
48
47
  end
49
48
 
49
+ should "not use $in for arrays if already using array operator" do
50
+ FinderOptions.to_mongo_criteria(:foo => {'$all' => [1,2,3]}).should == {
51
+ :foo => {'$all' => [1,2,3]}
52
+ }
53
+
54
+ FinderOptions.to_mongo_criteria(:foo => {'$any' => [1,2,3]}).should == {
55
+ :foo => {'$any' => [1,2,3]}
56
+ }
57
+ end
58
+
50
59
  should "work arbitrarily deep" do
51
60
  FinderOptions.to_mongo_criteria(:foo => {:bar => [1,2,3]}).should == {
52
61
  :foo => {:bar => {'$in' => [1,2,3]}}
53
62
  }
63
+
64
+ FinderOptions.to_mongo_criteria(:foo => {:bar => {'$any' => [1,2,3]}}).should == {
65
+ :foo => {:bar => {'$any' => [1,2,3]}}
66
+ }
54
67
  end
55
68
  end
56
69
 
@@ -90,6 +103,28 @@ class FinderOptionsTest < Test::Unit::TestCase
90
103
  hash[:baz] = 1
91
104
  FinderOptions.to_mongo_options(:order => 'foo desc, bar, baz')[:sort].should == hash
92
105
  end
106
+
107
+ should "just use sort if sort and order are present" do
108
+ FinderOptions.to_mongo_options(:sort => {'$natural' => 1}, :order => 'foo asc')[:sort].should == {
109
+ '$natural' => 1
110
+ }
111
+ end
112
+
113
+ should "convert natural in order to proper" do
114
+ hash = OrderedHash.new
115
+ hash[:'$natural'] = 1
116
+ FinderOptions.to_mongo_options(:order => '$natural asc')[:sort].should == hash
117
+ hash[:'$natural'] = -1
118
+ FinderOptions.to_mongo_options(:order => '$natural desc')[:sort].should == hash
119
+ end
120
+
121
+ should "work for natural order ascending" do
122
+ FinderOptions.to_mongo_options(:sort => {'$natural' => 1})[:sort]['$natural'].should == 1
123
+ end
124
+
125
+ should "work for natural order descending" do
126
+ FinderOptions.to_mongo_options(:sort => {'$natural' => -1})[:sort]['$natural'].should == -1
127
+ end
93
128
  end
94
129
 
95
130
  context "offset" do
@@ -14,7 +14,7 @@ class KeyTest < Test::Unit::TestCase
14
14
 
15
15
  context "The Key Class" do
16
16
  should "have the native types defined" do
17
- Key::NativeTypes.should == [String, Float, Time, Integer, Boolean, Array, Hash, Ref]
17
+ Key::NativeTypes.should == [String, Float, Time, Integer, Boolean, Array, Hash]
18
18
  end
19
19
  end
20
20
 
@@ -31,9 +31,37 @@ class KeyTest < Test::Unit::TestCase
31
31
  Key.new(:foo, Integer, :required => true).options[:required].should be(true)
32
32
  end
33
33
 
34
+ should "default options to {}" do
35
+ Key.new(:foo, Integer, nil).options.should == {}
36
+ end
37
+
34
38
  should "symbolize option keys" do
35
39
  Key.new(:foo, Integer, 'required' => true).options[:required].should be(true)
36
40
  end
41
+
42
+ should "work with just name" do
43
+ key = Key.new(:foo)
44
+ key.name.should == 'foo'
45
+ end
46
+
47
+ should "work with name and type" do
48
+ key = Key.new(:foo, String)
49
+ key.name.should == 'foo'
50
+ key.type.should == String
51
+ end
52
+
53
+ should "work with name, type, and options" do
54
+ key = Key.new(:foo, String, :required => true)
55
+ key.name.should == 'foo'
56
+ key.type.should == String
57
+ key.options[:required].should be_true
58
+ end
59
+
60
+ should "work with name and options" do
61
+ key = Key.new(:foo, :required => true)
62
+ key.name.should == 'foo'
63
+ key.options[:required].should be_true
64
+ end
37
65
  end
38
66
 
39
67
  context "A key" do
@@ -48,14 +76,19 @@ class KeyTest < Test::Unit::TestCase
48
76
  should "not be equal to another key with different type" do
49
77
  Key.new(:name, String).should_not == Key.new(:name, Integer)
50
78
  end
51
-
52
- should "know if it is native" do
53
- Key.new(:name, String).native?.should be_true
54
- end
55
-
56
- should "know if it is not native" do
57
- klass = Class.new
58
- Key.new(:name, klass).native?.should be_false
79
+
80
+ context "native?" do
81
+ should "be true if native type" do
82
+ Key.new(:name, String).native?.should be_true
83
+ end
84
+
85
+ should "be true if no type" do
86
+ Key.new(:name).native?.should be_true
87
+ end
88
+
89
+ should "be false if not native" do
90
+ Key.new(:name, Class.new).native?.should be_false
91
+ end
59
92
  end
60
93
 
61
94
  should "know if it is a embedded_document" do
@@ -84,6 +117,13 @@ class KeyTest < Test::Unit::TestCase
84
117
  key.set(a).should == 21
85
118
  end
86
119
  end
120
+
121
+ should "work fine with long integers" do
122
+ key = Key.new(:foo, Integer)
123
+ [9223372036854775807, '9223372036854775807'].each do |value|
124
+ key.set(value).should == 9223372036854775807
125
+ end
126
+ end
87
127
 
88
128
  should "correctly typecast Floats" do
89
129
  key = Key.new(:foo, Float)
@@ -97,9 +137,9 @@ class KeyTest < Test::Unit::TestCase
97
137
  key.set('2000-01-01 01:01:01.123456').should == Time.local(2000, 1, 1, 1, 1, 1, 123456)
98
138
  end
99
139
 
100
- should_eventually "correctly typecast Dates" do
101
- key = Key.new(:foo, Date)
102
- key.set('2000-01-01').should == Date.new(2000, 1, 1)
140
+ should "correctly typecast Times into UTC time zone" do
141
+ key = Key.new(:foo, Time)
142
+ key.set('2000-01-01 01:01:01.123456').zone.should == "UTC"
103
143
  end
104
144
 
105
145
  should "correctly typecast Boolean" do
@@ -134,6 +174,13 @@ class KeyTest < Test::Unit::TestCase
134
174
  key = Key.new(:foo, String)
135
175
  key.get('bar').should == 'bar'
136
176
  end
177
+
178
+ should "work without type" do
179
+ key = Key.new(:foo)
180
+ key.get([1,"2"]).should == [1, "2"]
181
+ key.get(false).should == false
182
+ key.get({}).should == {}
183
+ end
137
184
 
138
185
  context "for a key with a default value set" do
139
186
  setup do
File without changes
@@ -0,0 +1,113 @@
1
+ require 'test_helper'
2
+
3
+ class PaginationTest < Test::Unit::TestCase
4
+ context "Pagination proxy" do
5
+ include MongoMapper::Pagination
6
+
7
+ should "should have accessors for subject" do
8
+ subject = [1,2,3,4,5]
9
+ collection = PaginationProxy.new(25, 2)
10
+ collection.subject = subject
11
+ collection.subject.should == subject
12
+ end
13
+
14
+ should "delegate any methods not defined to the subject" do
15
+ subject = [1,2,3,4,5]
16
+ collection = PaginationProxy.new(25, 2, 10)
17
+ collection.subject = subject
18
+ collection.size.should == 5
19
+ collection.each_with_index do |value, i|
20
+ value.should == subject[i]
21
+ end
22
+ collection[0..2].should == [1,2,3]
23
+ collection.class.should == Array
24
+ end
25
+
26
+ should "return correct value for total_entries" do
27
+ PaginationProxy.new(25, 2, 10).total_entries.should == 25
28
+ PaginationProxy.new('25', 2, 10).total_entries.should == 25
29
+ end
30
+
31
+ should "return correct value for per_page" do
32
+ PaginationProxy.new(25, 2, 10).per_page.should == 10
33
+ PaginationProxy.new(25, 2, '10').per_page.should == 10
34
+ end
35
+
36
+ should "alias limit to per_page" do
37
+ PaginationProxy.new(100, 1, 300).limit.should == 300
38
+ end
39
+
40
+ should "set per_page to 25 if nil or blank" do
41
+ PaginationProxy.new(25, 2).per_page.should == 25
42
+ PaginationProxy.new(25, 2, '').per_page.should == 25
43
+ end
44
+
45
+ should "return correct value for current_page" do
46
+ PaginationProxy.new(25, 2, 10).current_page.should == 2
47
+ PaginationProxy.new(25, '2', 10).current_page.should == 2
48
+ end
49
+
50
+ should "not allow value less than 1 for current page" do
51
+ PaginationProxy.new(25, -1).current_page.should == 1
52
+ end
53
+
54
+ should "automatically calculate total_pages from total_entries and per page" do
55
+ PaginationProxy.new(25, 2, 10).total_pages.should == 3
56
+ end
57
+
58
+ should "know how many records to skip" do
59
+ PaginationProxy.new(25, 2, 10).skip.should == 10
60
+ end
61
+
62
+ should "alias offset to skip" do
63
+ PaginationProxy.new(25, 2, 10).offset.should == 10
64
+ end
65
+
66
+ context "previous_page" do
67
+ should "be nil if current page 1" do
68
+ PaginationProxy.new(25, 1, 10).previous_page.should be_nil
69
+ end
70
+
71
+ should "be one less than current page if current is > 1" do
72
+ PaginationProxy.new(25, 2, 10).previous_page.should == 1
73
+ end
74
+ end
75
+
76
+ context "next_page" do
77
+ should "be nil if current page is last page" do
78
+ PaginationProxy.new(25, 3, 10).next_page.should be_nil
79
+ end
80
+
81
+ should "work for any page that is not last" do
82
+ PaginationProxy.new(25, 1, 10).next_page.should == 2
83
+ PaginationProxy.new(25, 2, 10).next_page.should == 3
84
+ end
85
+ end
86
+
87
+ context "previous_page" do
88
+ should "be nil if current page is first page" do
89
+ PaginationProxy.new(25, 1, 10).previous_page.should be_nil
90
+ end
91
+
92
+ should "work for any page other than first" do
93
+ PaginationProxy.new(25, 2, 10).previous_page.should == 1
94
+ PaginationProxy.new(25, 3, 10).previous_page.should == 2
95
+ end
96
+ end
97
+
98
+ context "out_of_bounds?" do
99
+ should "be true if current_page is greater than total_pages" do
100
+ PaginationProxy.new(25, 10, 4).out_of_bounds?.should be_true
101
+ end
102
+
103
+ should "be false if current_page is less than total_pages" do
104
+ PaginationProxy.new(25, 10, 1).out_of_bounds?.should be_false
105
+ PaginationProxy.new(25, 2, 10).out_of_bounds?.should be_false
106
+ end
107
+
108
+ should "be false if current_page is equal to total_pages" do
109
+ PaginationProxy.new(25, 3, 10).out_of_bounds?.should be_false
110
+ end
111
+ end
112
+ end # end of pagination proxy
113
+ end # end of test case
@@ -0,0 +1,34 @@
1
+ require 'test_helper'
2
+
3
+ class TestRailsCompatibility < Test::Unit::TestCase
4
+ class Item
5
+ include MongoMapper::EmbeddedDocument
6
+ key :for_all, String
7
+ end
8
+
9
+ class FirstItem < Item
10
+ key :first_only, String
11
+ many :second_items
12
+ end
13
+
14
+ class SecondItem < Item
15
+ key :second_only, String
16
+ end
17
+
18
+ context "EmbeddedDocument" do
19
+ should "raise error for to_param as embedded do not have id's" do
20
+ lambda { Item.new.to_param }.should raise_error
21
+ end
22
+
23
+ should "alias many to has_many" do
24
+ FirstItem.should respond_to(:has_many)
25
+ FirstItem.method(:has_many).should == FirstItem.method(:many)
26
+ end
27
+
28
+ should "have column names" do
29
+ Item.column_names.sort.should == ['_id', 'for_all']
30
+ FirstItem.column_names.sort.should == ['_id', 'first_only', 'for_all']
31
+ SecondItem.column_names.sort.should == ['_id', 'for_all', 'second_only']
32
+ end
33
+ end
34
+ end
@@ -20,7 +20,6 @@ class SerializationTest < Test::Unit::TestCase
20
20
  )
21
21
  end
22
22
 
23
- # [:xml, :json].each do |format|
24
23
  [:json].each do |format|
25
24
  context format do
26
25
  should "be reversable" do
@@ -48,7 +47,6 @@ class SerializationTest < Test::Unit::TestCase
48
47
  assert_nil unserialized.age
49
48
  assert_equal @instance.awesome, unserialized.awesome
50
49
  end
51
-
52
50
  end
53
51
  end
54
52
  end
@@ -154,46 +154,6 @@ class ValidationsTest < Test::Unit::TestCase
154
154
  doc.should have_error_on(:name)
155
155
  end
156
156
  end
157
-
158
- context "validating uniqueness of" do
159
- setup do
160
- @document.key :name, String
161
- @document.validates_uniqueness_of :name
162
- end
163
-
164
- should "not fail if object is new" do
165
- doc = @document.new
166
- doc.should_not have_error_on(:name)
167
- end
168
-
169
- should "allow to update an object" do
170
- doc = @document.new("name" => "joe")
171
- doc.save
172
- doc.name = "joe"
173
- doc.valid?.should be_true
174
- doc.should_not have_error_on(:name)
175
- end
176
-
177
- should "fail if object name is not unique" do
178
- doc = @document.new("name" => "joe")
179
- doc.save.should be_true
180
- sleep 0.2 # hack to avoid race condition
181
- doc2 = @document.new("name" => "joe")
182
- doc2.should have_error_on(:name)
183
- end
184
- end
185
-
186
- context "validates uniqueness of with :unique shortcut" do
187
- should "work" do
188
- @document.key :name, String, :unique => true
189
-
190
- doc = @document.create(:name => 'John')
191
- doc.should_not have_error_on(:name)
192
- sleep 0.2 # hack to avoid race condition
193
- second_john = @document.create(:name => 'John')
194
- second_john.should have_error_on(:name, 'has already been taken')
195
- end
196
- end
197
157
 
198
158
  context "validating exclusion of" do
199
159
  should "throw error if enumerator not provided" do
@@ -274,70 +234,6 @@ class ValidationsTest < Test::Unit::TestCase
274
234
  end
275
235
  end # Validations
276
236
 
277
- context "Saving a new document that is invalid" do
278
- setup do
279
- @document = Class.new do
280
- include MongoMapper::Document
281
- key :name, String, :required => true
282
- end
283
-
284
- @document.collection.clear
285
- end
286
-
287
- should "not insert document" do
288
- doc = @document.new
289
- doc.save
290
- @document.count.should == 0
291
- end
292
-
293
- should "populate document's errors" do
294
- doc = @document.new
295
- doc.errors.size.should == 0
296
- doc.save
297
- doc.errors.full_messages.should == ["Name can't be empty"]
298
- end
299
- end
300
-
301
- context "Saving a document that is invalid (destructive)" do
302
- setup do
303
- @document = Class.new do
304
- include MongoMapper::Document
305
- key :name, String, :required => true
306
- end
307
-
308
- @document.collection.clear
309
- end
310
-
311
- should "raise error" do
312
- doc = @document.new
313
- lambda { doc.save! }.should raise_error(MongoMapper::DocumentNotValid)
314
- end
315
- end
316
-
317
- context "Saving an existing document that is invalid" do
318
- setup do
319
- @document = Class.new do
320
- include MongoMapper::Document
321
- key :name, String, :required => true
322
- end
323
-
324
- @document.collection.clear
325
- @doc = @document.create(:name => 'John Nunemaker')
326
- end
327
-
328
- should "not update document" do
329
- @doc.name = nil
330
- @doc.save
331
- @document.find(@doc.id).name.should == 'John Nunemaker'
332
- end
333
-
334
- should "populate document's errors" do
335
- @doc.name = nil
336
- @doc.save
337
- @doc.errors.full_messages.should == ["Name can't be empty"]
338
- end
339
- end
340
-
341
237
  context "Adding validation errors" do
342
238
  setup do
343
239
  @document = Class.new do
@@ -359,35 +255,5 @@ class ValidationsTest < Test::Unit::TestCase
359
255
  doc.action = 'kick'
360
256
  doc.should_not have_error_on(:action)
361
257
  end
362
-
363
- should "work with validate_on_create callback" do
364
- @document.validate_on_create :action_present
365
-
366
- doc = @document.new
367
- doc.action = nil
368
- doc.should have_error_on(:action)
369
-
370
- doc.action = 'kick'
371
- doc.should_not have_error_on(:action)
372
- doc.save
373
-
374
- doc.action = nil
375
- doc.should_not have_error_on(:action)
376
- end
377
-
378
- should "work with validate_on_update callback" do
379
- @document.validate_on_update :action_present
380
-
381
- doc = @document.new
382
- doc.action = nil
383
- doc.should_not have_error_on(:action)
384
- doc.save
385
-
386
- doc.action = nil
387
- doc.should have_error_on(:action)
388
-
389
- doc.action = 'kick'
390
- doc.should_not have_error_on(:action)
391
- end
392
258
  end
393
259
  end