mongo_mapper 0.6.10 → 0.7.0

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 (106) hide show
  1. data/README.rdoc +5 -14
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/lib/mongo_mapper.rb +48 -56
  5. data/lib/mongo_mapper/document.rb +136 -164
  6. data/lib/mongo_mapper/embedded_document.rb +29 -354
  7. data/lib/mongo_mapper/plugins.rb +31 -0
  8. data/lib/mongo_mapper/plugins/associations.rb +105 -0
  9. data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
  10. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  11. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  12. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  13. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +50 -0
  14. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  15. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  16. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  17. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  18. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  19. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  20. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  21. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  22. data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
  23. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  24. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  25. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  26. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  27. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  28. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  29. data/lib/mongo_mapper/plugins/keys.rb +324 -0
  30. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  31. data/lib/mongo_mapper/plugins/pagination.rb +24 -0
  32. data/lib/mongo_mapper/plugins/pagination/proxy.rb +68 -0
  33. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  34. data/lib/mongo_mapper/plugins/rails.rb +45 -0
  35. data/lib/mongo_mapper/plugins/serialization.rb +105 -0
  36. data/lib/mongo_mapper/plugins/validations.rb +46 -0
  37. data/lib/mongo_mapper/query.rb +130 -0
  38. data/lib/mongo_mapper/support.rb +40 -17
  39. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  40. data/lib/mongo_mapper/support/find.rb +77 -0
  41. data/mongo_mapper.gemspec +55 -38
  42. data/performance/read_write.rb +52 -0
  43. data/specs.watchr +23 -2
  44. data/test/functional/associations/test_belongs_to_proxy.rb +12 -10
  45. data/test/functional/associations/test_many_documents_as_proxy.rb +4 -21
  46. data/test/functional/associations/test_many_documents_proxy.rb +2 -8
  47. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +59 -39
  48. data/test/functional/associations/test_many_embedded_proxy.rb +145 -81
  49. data/test/functional/associations/test_many_polymorphic_proxy.rb +2 -40
  50. data/test/functional/associations/test_one_proxy.rb +25 -10
  51. data/test/functional/test_binary.rb +2 -8
  52. data/test/functional/test_callbacks.rb +1 -5
  53. data/test/functional/test_dirty.rb +27 -23
  54. data/test/functional/test_document.rb +224 -165
  55. data/test/functional/test_embedded_document.rb +72 -82
  56. data/test/functional/test_identity_map.rb +508 -0
  57. data/test/functional/test_modifiers.rb +15 -5
  58. data/test/functional/test_pagination.rb +1 -3
  59. data/test/functional/test_protected.rb +155 -0
  60. data/test/functional/test_string_id_compatibility.rb +7 -12
  61. data/test/functional/test_validations.rb +26 -58
  62. data/test/models.rb +0 -39
  63. data/test/test_helper.rb +37 -3
  64. data/test/unit/associations/test_base.rb +5 -5
  65. data/test/unit/associations/test_proxy.rb +8 -6
  66. data/test/unit/test_descendant_appends.rb +71 -0
  67. data/test/unit/test_document.rb +71 -76
  68. data/test/unit/test_dynamic_finder.rb +27 -29
  69. data/test/unit/test_embedded_document.rb +555 -601
  70. data/test/unit/{test_key.rb → test_keys.rb} +2 -5
  71. data/test/unit/test_mongo_mapper.rb +69 -9
  72. data/test/unit/test_pagination.rb +40 -32
  73. data/test/unit/test_plugins.rb +50 -0
  74. data/test/unit/{test_finder_options.rb → test_query.rb} +74 -65
  75. data/test/unit/test_rails.rb +123 -0
  76. data/test/unit/{test_serializations.rb → test_serialization.rb} +1 -2
  77. data/test/unit/test_support.rb +23 -7
  78. data/test/unit/test_time_zones.rb +3 -4
  79. data/test/unit/test_validations.rb +58 -17
  80. metadata +53 -36
  81. data/lib/mongo_mapper/associations.rb +0 -78
  82. data/lib/mongo_mapper/associations/base.rb +0 -119
  83. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +0 -26
  84. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +0 -21
  85. data/lib/mongo_mapper/associations/collection.rb +0 -19
  86. data/lib/mongo_mapper/associations/in_array_proxy.rb +0 -137
  87. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -26
  88. data/lib/mongo_mapper/associations/many_documents_proxy.rb +0 -115
  89. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +0 -31
  90. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +0 -54
  91. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +0 -11
  92. data/lib/mongo_mapper/associations/one_proxy.rb +0 -64
  93. data/lib/mongo_mapper/associations/proxy.rb +0 -116
  94. data/lib/mongo_mapper/callbacks.rb +0 -61
  95. data/lib/mongo_mapper/dirty.rb +0 -117
  96. data/lib/mongo_mapper/dynamic_finder.rb +0 -74
  97. data/lib/mongo_mapper/finder_options.rb +0 -145
  98. data/lib/mongo_mapper/key.rb +0 -36
  99. data/lib/mongo_mapper/mongo_mapper.rb +0 -125
  100. data/lib/mongo_mapper/pagination.rb +0 -66
  101. data/lib/mongo_mapper/rails_compatibility/document.rb +0 -15
  102. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +0 -28
  103. data/lib/mongo_mapper/serialization.rb +0 -54
  104. data/lib/mongo_mapper/serializers/json_serializer.rb +0 -48
  105. data/lib/mongo_mapper/validations.rb +0 -39
  106. data/test/functional/test_rails_compatibility.rb +0 -25
@@ -2,17 +2,13 @@ require 'test_helper'
2
2
 
3
3
  class ModifierTest < Test::Unit::TestCase
4
4
  def setup
5
- @page_class = Class.new do
6
- include MongoMapper::Document
7
-
5
+ @page_class = Doc do
8
6
  key :title, String
9
7
  key :day_count, Integer, :default => 0
10
8
  key :week_count, Integer, :default => 0
11
9
  key :month_count, Integer, :default => 0
12
10
  key :tags, Array
13
11
  end
14
-
15
- @page_class.collection.remove
16
12
  end
17
13
 
18
14
  def assert_page_counts(page, day_count, week_count, month_count)
@@ -239,4 +235,18 @@ class ModifierTest < Test::Unit::TestCase
239
235
  page2.reload
240
236
  page.tags.should == %w(foo)
241
237
  end
238
+
239
+ should "be able to remove the last element the array" do
240
+ page = @page_class.create(:title => 'Home', :tags => %w(foo bar))
241
+ @page_class.pop(page.id, :tags => 1)
242
+ page.reload
243
+ page.tags.should == %w(foo)
244
+ end
245
+
246
+ should "be able to remove the first element of the array" do
247
+ page = @page_class.create(:title => 'Home', :tags => %w(foo bar))
248
+ @page_class.pop(page.id, :tags => -1)
249
+ page.reload
250
+ page.tags.should == %w(bar)
251
+ end
242
252
  end
@@ -3,8 +3,7 @@ require 'test_helper'
3
3
  class PaginationTest < Test::Unit::TestCase
4
4
  context "Paginating" do
5
5
  setup do
6
- @document = Class.new do
7
- include MongoMapper::Document
6
+ @document = Doc do
8
7
  set_collection_name 'users'
9
8
 
10
9
  key :first_name, String
@@ -13,7 +12,6 @@ class PaginationTest < Test::Unit::TestCase
13
12
 
14
13
  def self.per_page; 1 end
15
14
  end
16
- @document.collection.remove
17
15
 
18
16
  @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
19
17
  @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
@@ -0,0 +1,155 @@
1
+ require 'test_helper'
2
+
3
+ class ProtectedTest < Test::Unit::TestCase
4
+ context 'A document with protected attributes' do
5
+ setup do
6
+ @doc_class = Doc do
7
+ key :name, String
8
+ key :admin, Boolean, :default => false
9
+
10
+ attr_protected :admin
11
+ end
12
+
13
+ @doc = @doc_class.create(:name => 'Steve Sloan')
14
+ end
15
+
16
+ should 'have protected attributes class method' do
17
+ @doc_class.protected_attributes.should == [:admin].to_set
18
+ end
19
+
20
+ should "default protected attributes to nil" do
21
+ Doc().protected_attributes.should be_nil
22
+ end
23
+
24
+ should "have protected attributes instance method" do
25
+ @doc.protected_attributes.should equal(@doc_class.protected_attributes)
26
+ end
27
+
28
+ should "work with :protected shortcut when defining key" do
29
+ Doc() do
30
+ key :user_id, ObjectId, :protected => true
31
+ end.protected_attributes.should == [:user_id].to_set
32
+ end
33
+
34
+ should 'assign protected attribute through accessor' do
35
+ @doc.admin = true
36
+ @doc.admin.should be_true
37
+ end
38
+
39
+ should "ignore protected attribute on #initialize" do
40
+ doc = @doc_class.new(:name => 'John', :admin => true)
41
+ doc.admin.should be_false
42
+ doc.name.should == 'John'
43
+ end
44
+
45
+ should "not ignore protected attributes on #initialize from the database" do
46
+ doc = @doc_class.new(:name => 'John')
47
+ doc.admin = true
48
+ doc.save!
49
+
50
+ doc = @doc_class.first(:name => 'John')
51
+ doc.admin.should be_true
52
+ doc.name.should == 'John'
53
+ end
54
+
55
+ should 'ignore protected attribute on #update_attributes' do
56
+ @doc.update_attributes(:name => 'Ren Hoek', :admin => true)
57
+ @doc.name.should == 'Ren Hoek'
58
+ @doc.admin.should be_false
59
+ end
60
+
61
+ should 'ignore protected attribute on #update_attributes!' do
62
+ @doc.update_attributes!(:name => 'Stimpson J. Cat', :admin => true)
63
+ @doc.name.should == 'Stimpson J. Cat'
64
+ @doc.admin.should be_false
65
+ end
66
+ end
67
+
68
+ context "Single collection inherited protected attributes" do
69
+ setup do
70
+ class ::GrandParent
71
+ include MongoMapper::Document
72
+
73
+ key :_type, String
74
+ key :site_id, ObjectId
75
+
76
+ attr_protected :site_id
77
+ end
78
+ GrandParent.collection.remove
79
+
80
+ class ::Child < ::GrandParent
81
+ key :position, Integer
82
+
83
+ attr_protected :position
84
+ end
85
+
86
+ class ::GrandChild < ::Child; end
87
+
88
+ class ::OtherChild < ::GrandParent
89
+ key :blog_id, ObjectId
90
+
91
+ attr_protected :blog_id
92
+ end
93
+ end
94
+
95
+ teardown do
96
+ Object.send :remove_const, 'GrandParent' if defined?(::GrandParent)
97
+ Object.send :remove_const, 'Child' if defined?(::Child)
98
+ Object.send :remove_const, 'GrandChild' if defined?(::GrandChild)
99
+ Object.send :remove_const, 'OtherChild' if defined?(::OtherChild)
100
+ end
101
+
102
+ should "share keys down the inheritance trail" do
103
+ GrandParent.protected_attributes.should == [:site_id].to_set
104
+ Child.protected_attributes.should == [:site_id, :position].to_set
105
+ GrandChild.protected_attributes.should == [:site_id, :position].to_set
106
+ OtherChild.protected_attributes.should == [:site_id, :blog_id].to_set
107
+ end
108
+ end
109
+
110
+ context 'An embedded document with protected attributes' do
111
+ setup do
112
+ @doc_class = Doc('Project')
113
+ @edoc_class = EDoc('Person') do
114
+ key :name, String
115
+ key :admin, Boolean, :default => false
116
+
117
+ attr_protected :admin
118
+ end
119
+ @doc_class.many :people, :class => @edoc_class
120
+
121
+ @doc = @doc_class.create(:title => 'MongoMapper')
122
+ @edoc = @edoc_class.new(:name => 'Steve Sloan')
123
+ @doc.people << @edoc
124
+ end
125
+
126
+ should 'have protected attributes class method' do
127
+ @edoc_class.protected_attributes.should == [:admin].to_set
128
+ end
129
+
130
+ should "default protected attributes to nil" do
131
+ EDoc().protected_attributes.should be_nil
132
+ end
133
+
134
+ should "have protected attributes instance method" do
135
+ @edoc.protected_attributes.should equal(@edoc_class.protected_attributes)
136
+ end
137
+
138
+ should 'assign protected attribute through accessor' do
139
+ @edoc.admin = true
140
+ @edoc.admin.should be_true
141
+ end
142
+
143
+ should 'ignore protected attribute on #update_attributes' do
144
+ @edoc.update_attributes(:name => 'Ren Hoek', :admin => true)
145
+ @edoc.name.should == 'Ren Hoek'
146
+ @edoc.admin.should be_false
147
+ end
148
+
149
+ should 'ignore protected attribute on #update_attributes!' do
150
+ @edoc.update_attributes!(:name => 'Stimpson J. Cat', :admin => true)
151
+ @edoc.name.should == 'Stimpson J. Cat'
152
+ @edoc.admin.should be_false
153
+ end
154
+ end
155
+ end
@@ -2,29 +2,24 @@ require 'test_helper'
2
2
 
3
3
  class StringIdCompatibilityTest < Test::Unit::TestCase
4
4
  def setup
5
- @note_class = Class.new do
6
- include MongoMapper::EmbeddedDocument
5
+ @note_class = EDoc do
7
6
  key :_id, String
8
7
  end
9
8
 
10
- @task_class = Class.new do
11
- include MongoMapper::Document
9
+ @task_class = Doc do
12
10
  key :_id, String
13
11
  key :project_id, String
14
12
  belongs_to :project
15
13
  end
16
14
 
17
- @project_class = Class.new do
15
+ @project_class = Doc do
18
16
  include MongoMapper::Document
19
17
  key :_id, String
20
18
  end
21
19
 
22
20
  @task_class.belongs_to :project, :class => @project_class
23
21
  @project_class.many :notes, :class => @note_class
24
- @project_class.many :tasks, :class => @task_class, :foreign_key => 'project_id'
25
-
26
- @project_class.collection.remove
27
- @task_class.collection.remove
22
+ @project_class.many :tasks, :class => @task_class, :foreign_key => 'project_id', :order => :position.asc
28
23
  end
29
24
 
30
25
  should "assign correct _id for documents" do
@@ -60,9 +55,9 @@ class StringIdCompatibilityTest < Test::Unit::TestCase
60
55
  end
61
56
 
62
57
  should "be able to associate records" do
63
- t1 = @task_class.new(:body => 'First task')
64
- t2 = @task_class.new(:body => 'Second task')
65
- t3 = @task_class.new(:body => 'Third task')
58
+ t1 = @task_class.new(:body => 'First task', :position => 1)
59
+ t2 = @task_class.new(:body => 'Second task', :position => 2)
60
+ t3 = @task_class.new(:body => 'Third task', :position => 3)
66
61
  project = @project_class.create(:name => 'MM', :tasks => [t1, t2, t3])
67
62
 
68
63
  project = project.reload
@@ -3,12 +3,9 @@ require 'test_helper'
3
3
  class ValidationsTest < Test::Unit::TestCase
4
4
  context "Saving a new document that is invalid" do
5
5
  setup do
6
- @document = Class.new do
7
- include MongoMapper::Document
8
- set_collection_name 'test'
6
+ @document = Doc do
9
7
  key :name, String, :required => true
10
8
  end
11
- @document.collection.remove
12
9
  end
13
10
 
14
11
  should "not insert document" do
@@ -27,12 +24,9 @@ class ValidationsTest < Test::Unit::TestCase
27
24
 
28
25
  context "Saving a document that is invalid (destructive)" do
29
26
  setup do
30
- @document = Class.new do
31
- include MongoMapper::Document
32
- set_collection_name 'test'
27
+ @document = Doc do
33
28
  key :name, String, :required => true
34
29
  end
35
- @document.collection.remove
36
30
  end
37
31
 
38
32
  should "raise error" do
@@ -43,12 +37,9 @@ class ValidationsTest < Test::Unit::TestCase
43
37
 
44
38
  context "Creating a document that is invalid (destructive)" do
45
39
  setup do
46
- @document = Class.new do
47
- include MongoMapper::Document
48
- set_collection_name 'test'
40
+ @document = Doc do
49
41
  key :name, String, :required => true
50
42
  end
51
- @document.collection.remove
52
43
  end
53
44
 
54
45
  should "raise error" do
@@ -63,12 +54,9 @@ class ValidationsTest < Test::Unit::TestCase
63
54
 
64
55
  context "Saving an existing document that is invalid" do
65
56
  setup do
66
- @document = Class.new do
67
- include MongoMapper::Document
68
- set_collection_name 'test'
57
+ @document = Doc do
69
58
  key :name, String, :required => true
70
59
  end
71
- @document.collection.remove
72
60
 
73
61
  @doc = @document.create(:name => 'John Nunemaker')
74
62
  end
@@ -88,16 +76,12 @@ class ValidationsTest < Test::Unit::TestCase
88
76
 
89
77
  context "Adding validation errors" do
90
78
  setup do
91
- @document = Class.new do
92
- include MongoMapper::Document
93
- set_collection_name 'test'
94
-
79
+ @document = Doc do
95
80
  key :action, String
96
81
  def action_present
97
82
  errors.add(:action, 'is invalid') if action.blank?
98
83
  end
99
84
  end
100
- @document.collection.remove
101
85
  end
102
86
 
103
87
  should "work with validate_on_create callback" do
@@ -133,14 +117,10 @@ class ValidationsTest < Test::Unit::TestCase
133
117
 
134
118
  context "validating uniqueness of" do
135
119
  setup do
136
- @document = Class.new do
137
- include MongoMapper::Document
138
- set_collection_name 'test'
139
-
120
+ @document = Doc do
140
121
  key :name, String
141
122
  validates_uniqueness_of :name
142
123
  end
143
- @document.collection.remove
144
124
  end
145
125
 
146
126
  should "not fail if object is new" do
@@ -149,10 +129,7 @@ class ValidationsTest < Test::Unit::TestCase
149
129
  end
150
130
 
151
131
  should "not fail when new object is out of scope" do
152
- document = Class.new do
153
- include MongoMapper::Document
154
- set_collection_name 'test'
155
-
132
+ document = Doc do
156
133
  key :name
157
134
  key :adult
158
135
  validates_uniqueness_of :name, :scope => :adult
@@ -162,7 +139,6 @@ class ValidationsTest < Test::Unit::TestCase
162
139
 
163
140
  doc2 = document.new("name" => "joe", :adult => false)
164
141
  doc2.should be_valid
165
-
166
142
  end
167
143
 
168
144
  should "allow to update an object" do
@@ -193,10 +169,7 @@ class ValidationsTest < Test::Unit::TestCase
193
169
  end
194
170
 
195
171
  should "allow multiple blank entries if :allow_blank => true" do
196
- document = Class.new do
197
- include MongoMapper::Document
198
- set_collection_name 'test'
199
-
172
+ document = Doc do
200
173
  key :name
201
174
  validates_uniqueness_of :name, :allow_blank => :true
202
175
  end
@@ -213,11 +186,21 @@ class ValidationsTest < Test::Unit::TestCase
213
186
  doc2.should_not have_error_on(:name)
214
187
  end
215
188
 
216
- should "allow entries that differ only in case by default" do
217
- document = Class.new do
218
- include MongoMapper::Document
219
- set_collection_name 'test'
189
+ should "allow multiple nil entries if :allow_nil => true" do
190
+ document = Doc do
191
+ key :name
192
+ validates_uniqueness_of :name, :allow_nil => :true
193
+ end
220
194
 
195
+ doc = document.new('name' => nil)
196
+ doc.save.should be_true
197
+
198
+ doc2 = document.new('name' => nil)
199
+ doc2.should_not have_error_on(:name)
200
+ end
201
+
202
+ should "allow entries that differ only in case by default" do
203
+ document = Doc do
221
204
  key :name
222
205
  validates_uniqueness_of :name
223
206
  end
@@ -231,10 +214,7 @@ class ValidationsTest < Test::Unit::TestCase
231
214
 
232
215
  context "with :case_sensitive => false" do
233
216
  setup do
234
- @document = Class.new do
235
- include MongoMapper::Document
236
- set_collection_name 'test'
237
-
217
+ @document = Doc do
238
218
  key :name
239
219
  validates_uniqueness_of :name, :case_sensitive => false
240
220
  end
@@ -256,15 +236,11 @@ class ValidationsTest < Test::Unit::TestCase
256
236
 
257
237
  context "scoped by a single attribute" do
258
238
  setup do
259
- @document = Class.new do
260
- include MongoMapper::Document
261
- set_collection_name 'test'
262
-
239
+ @document = Doc do
263
240
  key :name, String
264
241
  key :scope, String
265
242
  validates_uniqueness_of :name, :scope => :scope
266
243
  end
267
- @document.collection.remove
268
244
  end
269
245
 
270
246
  should "fail if the same name exists in the scope" do
@@ -296,16 +272,12 @@ class ValidationsTest < Test::Unit::TestCase
296
272
 
297
273
  context "scoped by a multiple attributes" do
298
274
  setup do
299
- @document = Class.new do
300
- include MongoMapper::Document
301
- set_collection_name 'test'
302
-
275
+ @document = Doc do
303
276
  key :name, String
304
277
  key :first_scope, String
305
278
  key :second_scope, String
306
279
  validates_uniqueness_of :name, :scope => [:first_scope, :second_scope]
307
280
  end
308
- @document.collection.remove
309
281
  end
310
282
 
311
283
  should "fail if the same name exists in the scope" do
@@ -338,13 +310,9 @@ class ValidationsTest < Test::Unit::TestCase
338
310
 
339
311
  context "validates uniqueness of with :unique shortcut" do
340
312
  should "work" do
341
- @document = Class.new do
342
- include MongoMapper::Document
343
- set_collection_name 'test'
344
-
313
+ @document = Doc do
345
314
  key :name, String, :unique => true
346
315
  end
347
- @document.collection.remove
348
316
 
349
317
  doc = @document.create(:name => 'John')
350
318
  doc.should_not have_error_on(:name)