mongo_mapper 0.12.0 → 0.13.0.beta1

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 (154) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +35 -13
  3. data/bin/mmconsole +1 -1
  4. data/lib/mongo_mapper.rb +4 -0
  5. data/lib/mongo_mapper/connection.rb +17 -6
  6. data/lib/mongo_mapper/document.rb +1 -0
  7. data/lib/mongo_mapper/exceptions.rb +4 -1
  8. data/lib/mongo_mapper/extensions/binary.rb +1 -1
  9. data/lib/mongo_mapper/extensions/boolean.rb +20 -23
  10. data/lib/mongo_mapper/extensions/date.rb +3 -3
  11. data/lib/mongo_mapper/extensions/integer.rb +5 -1
  12. data/lib/mongo_mapper/extensions/kernel.rb +2 -0
  13. data/lib/mongo_mapper/extensions/ordered_hash.rb +23 -0
  14. data/lib/mongo_mapper/extensions/string.rb +2 -2
  15. data/lib/mongo_mapper/extensions/time.rb +7 -5
  16. data/lib/mongo_mapper/middleware/identity_map.rb +3 -4
  17. data/lib/mongo_mapper/plugins.rb +1 -1
  18. data/lib/mongo_mapper/plugins/associations.rb +11 -5
  19. data/lib/mongo_mapper/plugins/associations/base.rb +5 -3
  20. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +0 -0
  21. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +8 -8
  22. data/lib/mongo_mapper/plugins/associations/collection.rb +2 -0
  23. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +32 -7
  24. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +2 -2
  25. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +12 -12
  26. data/lib/mongo_mapper/plugins/associations/proxy.rb +5 -1
  27. data/lib/mongo_mapper/plugins/associations/single_association.rb +6 -6
  28. data/lib/mongo_mapper/plugins/clone.rb +4 -2
  29. data/lib/mongo_mapper/plugins/dirty.rb +22 -21
  30. data/lib/mongo_mapper/plugins/document.rb +4 -4
  31. data/lib/mongo_mapper/plugins/dumpable.rb +22 -0
  32. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +58 -9
  33. data/lib/mongo_mapper/plugins/identity_map.rb +42 -32
  34. data/lib/mongo_mapper/plugins/keys.rb +133 -54
  35. data/lib/mongo_mapper/plugins/keys/key.rb +68 -22
  36. data/lib/mongo_mapper/plugins/modifiers.rb +26 -19
  37. data/lib/mongo_mapper/plugins/persistence.rb +15 -5
  38. data/lib/mongo_mapper/plugins/querying.rb +15 -40
  39. data/lib/mongo_mapper/plugins/querying/{decorator.rb → decorated_plucky_query.rb} +24 -4
  40. data/lib/mongo_mapper/plugins/rails.rb +22 -2
  41. data/lib/mongo_mapper/plugins/safe.rb +8 -5
  42. data/lib/mongo_mapper/plugins/sci.rb +26 -4
  43. data/lib/mongo_mapper/plugins/scopes.rb +5 -4
  44. data/lib/mongo_mapper/plugins/timestamps.rb +11 -4
  45. data/lib/mongo_mapper/plugins/validations.rb +1 -1
  46. data/lib/mongo_mapper/utils.rb +12 -0
  47. data/lib/mongo_mapper/version.rb +1 -1
  48. data/lib/rails/generators/mongo_mapper/config/config_generator.rb +20 -7
  49. data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +6 -0
  50. data/lib/rails/generators/mongo_mapper/model/model_generator.rb +18 -1
  51. data/lib/rails/generators/mongo_mapper/model/templates/model.rb +9 -5
  52. data/{test/functional/test_accessible.rb → spec/functional/accessible_spec.rb} +29 -29
  53. data/{test/functional/associations/test_belongs_to_polymorphic_proxy.rb → spec/functional/associations/belongs_to_polymorphic_proxy_spec.rb} +10 -10
  54. data/{test/functional/associations/test_belongs_to_proxy.rb → spec/functional/associations/belongs_to_proxy_spec.rb} +82 -64
  55. data/{test/functional/associations/test_in_array_proxy.rb → spec/functional/associations/in_array_proxy_spec.rb} +68 -68
  56. data/{test/functional/associations/test_many_documents_as_proxy.rb → spec/functional/associations/many_documents_as_proxy_spec.rb} +37 -38
  57. data/{test/functional/associations/test_many_documents_proxy.rb → spec/functional/associations/many_documents_proxy_spec.rb} +233 -146
  58. data/{test/functional/associations/test_many_embedded_polymorphic_proxy.rb → spec/functional/associations/many_embedded_polymorphic_proxy_spec.rb} +19 -20
  59. data/{test/functional/associations/test_many_embedded_proxy.rb → spec/functional/associations/many_embedded_proxy_spec.rb} +23 -24
  60. data/{test/functional/associations/test_many_polymorphic_proxy.rb → spec/functional/associations/many_polymorphic_proxy_spec.rb} +45 -46
  61. data/{test/functional/associations/test_one_as_proxy.rb → spec/functional/associations/one_as_proxy_spec.rb} +75 -77
  62. data/{test/functional/associations/test_one_embedded_polymorphic_proxy.rb → spec/functional/associations/one_embedded_polymorphic_proxy_spec.rb} +31 -32
  63. data/{test/functional/associations/test_one_embedded_proxy.rb → spec/functional/associations/one_embedded_proxy_spec.rb} +10 -10
  64. data/{test/functional/associations/test_one_proxy.rb → spec/functional/associations/one_proxy_spec.rb} +125 -102
  65. data/spec/functional/associations_spec.rb +48 -0
  66. data/{test/functional/test_binary.rb → spec/functional/binary_spec.rb} +6 -6
  67. data/spec/functional/caching_spec.rb +75 -0
  68. data/{test/functional/test_callbacks.rb → spec/functional/callbacks_spec.rb} +84 -26
  69. data/{test/functional/test_dirty.rb → spec/functional/dirty_spec.rb} +57 -42
  70. data/{test/functional/test_document.rb → spec/functional/document_spec.rb} +52 -52
  71. data/spec/functional/dumpable_spec.rb +24 -0
  72. data/{test/functional/test_dynamic_querying.rb → spec/functional/dynamic_querying_spec.rb} +14 -14
  73. data/{test/functional/test_embedded_document.rb → spec/functional/embedded_document_spec.rb} +51 -42
  74. data/{test/functional/test_equality.rb → spec/functional/equality_spec.rb} +4 -4
  75. data/spec/functional/extensions_spec.rb +16 -0
  76. data/{test/functional/test_identity_map.rb → spec/functional/identity_map_spec.rb} +73 -61
  77. data/spec/functional/indexes_spec.rb +48 -0
  78. data/spec/functional/keys_spec.rb +224 -0
  79. data/{test/functional/test_logger.rb → spec/functional/logger_spec.rb} +6 -6
  80. data/spec/functional/modifiers_spec.rb +550 -0
  81. data/spec/functional/pagination_spec.rb +89 -0
  82. data/spec/functional/protected_spec.rb +199 -0
  83. data/spec/functional/querying_spec.rb +1003 -0
  84. data/spec/functional/rails_spec.rb +55 -0
  85. data/spec/functional/safe_spec.rb +163 -0
  86. data/{test/functional/test_sci.rb → spec/functional/sci_spec.rb} +123 -34
  87. data/{test/functional/test_scopes.rb → spec/functional/scopes_spec.rb} +59 -26
  88. data/spec/functional/timestamps_spec.rb +97 -0
  89. data/{test/functional/test_touch.rb → spec/functional/touch_spec.rb} +13 -13
  90. data/spec/functional/userstamps_spec.rb +46 -0
  91. data/{test/functional/test_validations.rb → spec/functional/validations_spec.rb} +64 -64
  92. data/spec/spec_helper.rb +81 -0
  93. data/spec/support/matchers.rb +24 -0
  94. data/{test → spec/support}/models.rb +1 -6
  95. data/spec/unit/associations/base_spec.rb +146 -0
  96. data/spec/unit/associations/belongs_to_association_spec.rb +30 -0
  97. data/spec/unit/associations/many_association_spec.rb +64 -0
  98. data/spec/unit/associations/one_association_spec.rb +48 -0
  99. data/{test/unit/associations/test_proxy.rb → spec/unit/associations/proxy_spec.rb} +21 -21
  100. data/{test/unit/test_clone.rb → spec/unit/clone_spec.rb} +21 -11
  101. data/spec/unit/config_generator_spec.rb +24 -0
  102. data/{test/unit/test_document.rb → spec/unit/document_spec.rb} +42 -42
  103. data/{test/unit/test_dynamic_finder.rb → spec/unit/dynamic_finder_spec.rb} +28 -28
  104. data/{test/unit/test_embedded_document.rb → spec/unit/embedded_document_spec.rb} +102 -108
  105. data/{test/unit/test_equality.rb → spec/unit/equality_spec.rb} +7 -7
  106. data/{test/unit/test_exceptions.rb → spec/unit/exceptions_spec.rb} +3 -3
  107. data/{test/unit/test_extensions.rb → spec/unit/extensions_spec.rb} +85 -71
  108. data/spec/unit/identity_map_middleware_spec.rb +134 -0
  109. data/{test/unit/test_inspect.rb → spec/unit/inspect_spec.rb} +8 -8
  110. data/{test/unit/test_key.rb → spec/unit/key_spec.rb} +82 -52
  111. data/spec/unit/keys_spec.rb +155 -0
  112. data/spec/unit/model_generator_spec.rb +47 -0
  113. data/spec/unit/mongo_mapper_spec.rb +184 -0
  114. data/spec/unit/pagination_spec.rb +11 -0
  115. data/{test/unit/test_plugins.rb → spec/unit/plugins_spec.rb} +14 -14
  116. data/spec/unit/rails_compatibility_spec.rb +40 -0
  117. data/{test/unit/test_rails_reflect_on_association.rb → spec/unit/rails_reflect_on_association_spec.rb} +9 -9
  118. data/{test/unit/test_rails.rb → spec/unit/rails_spec.rb} +31 -31
  119. data/spec/unit/serialization_spec.rb +169 -0
  120. data/spec/unit/serializers/json_serializer_spec.rb +218 -0
  121. data/spec/unit/serializers/xml_serializer_spec.rb +198 -0
  122. data/{test/unit/test_time_zones.rb → spec/unit/time_zones_spec.rb} +8 -8
  123. data/{test/unit/test_translation.rb → spec/unit/translation_spec.rb} +6 -6
  124. data/{test/unit/test_validations.rb → spec/unit/validations_spec.rb} +72 -59
  125. metadata +199 -179
  126. data/test/_NOTE_ON_TESTING +0 -1
  127. data/test/functional/test_associations.rb +0 -46
  128. data/test/functional/test_caching.rb +0 -77
  129. data/test/functional/test_indexes.rb +0 -50
  130. data/test/functional/test_modifiers.rb +0 -537
  131. data/test/functional/test_pagination.rb +0 -91
  132. data/test/functional/test_protected.rb +0 -201
  133. data/test/functional/test_querying.rb +0 -935
  134. data/test/functional/test_safe.rb +0 -76
  135. data/test/functional/test_timestamps.rb +0 -62
  136. data/test/functional/test_userstamps.rb +0 -44
  137. data/test/support/railtie.rb +0 -4
  138. data/test/support/railtie/autoloaded.rb +0 -2
  139. data/test/support/railtie/not_autoloaded.rb +0 -3
  140. data/test/support/railtie/parent.rb +0 -3
  141. data/test/test_active_model_lint.rb +0 -18
  142. data/test/test_helper.rb +0 -93
  143. data/test/unit/associations/test_base.rb +0 -146
  144. data/test/unit/associations/test_belongs_to_association.rb +0 -29
  145. data/test/unit/associations/test_many_association.rb +0 -63
  146. data/test/unit/associations/test_one_association.rb +0 -47
  147. data/test/unit/serializers/test_json_serializer.rb +0 -216
  148. data/test/unit/serializers/test_xml_serializer.rb +0 -196
  149. data/test/unit/test_identity_map_middleware.rb +0 -132
  150. data/test/unit/test_keys.rb +0 -65
  151. data/test/unit/test_mongo_mapper.rb +0 -157
  152. data/test/unit/test_pagination.rb +0 -11
  153. data/test/unit/test_rails_compatibility.rb +0 -38
  154. data/test/unit/test_serialization.rb +0 -166
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Pagination" do
4
+ before do
5
+ @document = Doc do
6
+ key :first_name, String
7
+ key :last_name, String
8
+ key :age, Integer
9
+
10
+ def self.per_page; 1 end
11
+ end
12
+
13
+ @doc1 = @document.create(:first_name => 'John', :last_name => 'Nunemaker', :age => '27')
14
+ @doc2 = @document.create(:first_name => 'Steve', :last_name => 'Smith', :age => '28')
15
+ @doc3 = @document.create(:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26')
16
+ end
17
+
18
+ it "should return the total pages" do
19
+ result = @document.paginate(:per_page => 2, :page => 1)
20
+ result.total_pages.should == 2
21
+ end
22
+
23
+ it "should return the total pages when defaulting to the document class per_page" do
24
+ result = @document.paginate(:page => 1)
25
+ result.total_pages.should == 3
26
+ end
27
+
28
+ it "should return the total of records" do
29
+ result = @document.paginate(:per_page => 2, :page => 1)
30
+ result.total_entries.should == 3
31
+ end
32
+
33
+ it "should return the items" do
34
+ result = @document.paginate(:per_page => 2, :page => 1, :order => 'first_name')
35
+ result.size.should == 2
36
+ result.should == [@doc1, @doc3]
37
+ end
38
+
39
+ it "should accept conditions" do
40
+ result = @document.paginate({
41
+ :last_name => 'Nunemaker',
42
+ :order => "age DESC",
43
+ :per_page => 2,
44
+ :page => 1,
45
+ })
46
+ result.should == [@doc1, @doc3]
47
+ result.first.age.should == 27
48
+
49
+ result = @document.paginate({
50
+ :conditions => {:last_name => 'Nunemaker'},
51
+ :order => "age DESC",
52
+ :per_page => 2,
53
+ :page => 1} )
54
+ result.should == [@doc1, @doc3]
55
+ result.first.age.should == 27
56
+ end
57
+
58
+ it "should withstand rigor" do
59
+ result = @document.paginate({
60
+ :per_page => 1,
61
+ :page => 1,
62
+ :order => 'age desc',
63
+ :last_name => 'Nunemaker'
64
+ })
65
+ result.should == [@doc1]
66
+ result.total_entries.should == 2
67
+ result.total_pages.should == 2
68
+
69
+ result = @document.paginate({
70
+ :per_page => 1,
71
+ :page => 2,
72
+ :order => 'age desc',
73
+ :last_name => 'Nunemaker'
74
+ })
75
+ result.should == [@doc3]
76
+ result.total_entries.should == 2
77
+ result.total_pages.should == 2
78
+
79
+ result = @document.paginate({
80
+ :per_page => 2,
81
+ :page => 1,
82
+ :order => 'age desc',
83
+ :last_name => 'Nunemaker'
84
+ })
85
+ result.should == [@doc1, @doc3]
86
+ result.total_entries.should == 2
87
+ result.total_pages.should == 1
88
+ end
89
+ end
@@ -0,0 +1,199 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'A document with protected attributes' do
4
+ before do
5
+ @doc_class = Doc do
6
+ key :name, String
7
+ key :admin, Boolean, :default => false
8
+
9
+ attr_protected :admin
10
+ end
11
+
12
+ @doc = @doc_class.create(:name => 'Steve Sloan')
13
+ end
14
+
15
+ it "should have protected attributes class method" do
16
+ @doc_class.protected_attributes.should == [:admin].to_set
17
+ end
18
+
19
+ it "should default protected attributes to nil" do
20
+ Doc().protected_attributes.should be_nil
21
+ end
22
+
23
+ it "should have protected attributes instance method" do
24
+ @doc.protected_attributes.should equal(@doc_class.protected_attributes)
25
+ end
26
+
27
+ it "should raise error if there are accessible attributes" do
28
+ doc = Doc('Post')
29
+ doc.attr_accessible :name
30
+ lambda { doc.attr_protected :admin }.
31
+ should raise_error(/Declare either attr_protected or attr_accessible for Post/)
32
+ end
33
+
34
+ it "should know if using protected attributes" do
35
+ @doc_class.protected_attributes?.should be(true)
36
+ Doc().protected_attributes?.should be(false)
37
+ end
38
+
39
+ it "should work with :protected shortcut when defining key" do
40
+ Doc() do
41
+ key :user_id, ObjectId, :protected => true
42
+ end.protected_attributes.should == [:user_id].to_set
43
+ end
44
+
45
+ it "should assign protected attribute through accessor" do
46
+ @doc.admin = true
47
+ @doc.admin.should be_true
48
+ end
49
+
50
+ it "should ignore protected attribute on #initialize" do
51
+ doc = @doc_class.new(:name => 'John', :admin => true)
52
+ doc.admin.should be_false
53
+ doc.name.should == 'John'
54
+ end
55
+
56
+ it "should not ignore protected attributes on #initialize from the database" do
57
+ doc = @doc_class.new(:name => 'John')
58
+ doc.admin = true
59
+ doc.save!
60
+
61
+ doc = @doc_class.first(:name => 'John')
62
+ doc.admin.should be_true
63
+ doc.name.should == 'John'
64
+ end
65
+
66
+ it "should not ignore protected attributes on #reload" do
67
+ doc = @doc_class.new(:name => 'John')
68
+ doc.admin = true
69
+ doc.save!
70
+
71
+ doc.reload
72
+ doc.admin.should be_true
73
+ doc.name.should == 'John'
74
+ end
75
+
76
+ it "should ignore protected attribute on #update_attribute" do
77
+ @doc.update_attribute('admin', true)
78
+ @doc.admin.should be_true
79
+ end
80
+
81
+ it "should ignore protected attribute on #update_attributes" do
82
+ @doc.update_attributes(:name => 'Ren Hoek', :admin => true)
83
+ @doc.name.should == 'Ren Hoek'
84
+ @doc.admin.should be_false
85
+ end
86
+
87
+ it "should ignore protected attribute on #update_attributes!" do
88
+ @doc.update_attributes!(:name => 'Stimpson J. Cat', :admin => true)
89
+ @doc.name.should == 'Stimpson J. Cat'
90
+ @doc.admin.should be_false
91
+ end
92
+
93
+ it "should ignore protecteds attribute on #attributes=" do
94
+ @doc.attributes = {:name => 'Stimpson J. Cat', :admin => true}
95
+ @doc.name.should == 'Stimpson J. Cat'
96
+ @doc.admin.should be_false
97
+ end
98
+
99
+ it "should be indifferent to whether the protected keys are strings or symbols" do
100
+ @doc.update_attributes!("name" => 'Stimpson J. Cat', "admin" => true)
101
+ @doc.name.should == 'Stimpson J. Cat'
102
+ @doc.admin.should be_false
103
+ end
104
+
105
+ it "should accept nil as constructor's argument without raising exception" do
106
+ lambda { @doc_class.new(nil) }.should_not raise_error
107
+ end
108
+ end
109
+
110
+ describe "Single collection inherited protected attributes" do
111
+ before do
112
+ class ::GrandParent
113
+ include MongoMapper::Document
114
+
115
+ key :site_id, ObjectId
116
+ attr_protected :site_id
117
+ end
118
+ GrandParent.collection.remove
119
+
120
+ class ::Child < ::GrandParent
121
+ key :position, Integer
122
+
123
+ attr_protected :position
124
+ end
125
+
126
+ class ::GrandChild < ::Child; end
127
+
128
+ class ::OtherChild < ::GrandParent
129
+ key :blog_id, ObjectId
130
+
131
+ attr_protected :blog_id
132
+ end
133
+ end
134
+
135
+ after do
136
+ Object.send :remove_const, 'GrandParent' if defined?(::GrandParent)
137
+ Object.send :remove_const, 'Child' if defined?(::Child)
138
+ Object.send :remove_const, 'GrandChild' if defined?(::GrandChild)
139
+ Object.send :remove_const, 'OtherChild' if defined?(::OtherChild)
140
+ end
141
+
142
+ it "should share keys down the inheritance trail" do
143
+ GrandParent.protected_attributes.should == [:site_id].to_set
144
+ Child.protected_attributes.should == [:site_id, :position].to_set
145
+ GrandChild.protected_attributes.should == [:site_id, :position].to_set
146
+ OtherChild.protected_attributes.should == [:site_id, :blog_id].to_set
147
+ end
148
+ end
149
+
150
+ describe 'An embedded document with protected attributes' do
151
+ before do
152
+ @doc_class = Doc('Project')
153
+ @edoc_class = EDoc('Person') do
154
+ key :name, String
155
+ key :admin, Boolean, :default => false
156
+
157
+ attr_protected :admin
158
+ end
159
+ @doc_class.many :people, :class => @edoc_class
160
+
161
+ @doc = @doc_class.create(:title => 'MongoMapper')
162
+ @edoc = @edoc_class.new(:name => 'Steve Sloan')
163
+ @doc.people << @edoc
164
+ end
165
+
166
+ it "should have protected attributes class method" do
167
+ @edoc_class.protected_attributes.should == [:admin].to_set
168
+ end
169
+
170
+ it "should default protected attributes to nil" do
171
+ EDoc().protected_attributes.should be_nil
172
+ end
173
+
174
+ it "should have protected attributes instance method" do
175
+ @edoc.protected_attributes.should equal(@edoc_class.protected_attributes)
176
+ end
177
+
178
+ it "should assign protected attribute through accessor" do
179
+ @edoc.admin = true
180
+ @edoc.admin.should be_true
181
+ end
182
+
183
+ it "should not ignore protected attribute on #update_attribute" do
184
+ @edoc.update_attribute('admin', true)
185
+ @edoc.admin.should be_true
186
+ end
187
+
188
+ it "should ignore protected attribute on #update_attributes" do
189
+ @edoc.update_attributes(:name => 'Ren Hoek', :admin => true)
190
+ @edoc.name.should == 'Ren Hoek'
191
+ @edoc.admin.should be_false
192
+ end
193
+
194
+ it "should ignore protected attribute on #update_attributes!" do
195
+ @edoc.update_attributes!(:name => 'Stimpson J. Cat', :admin => true)
196
+ @edoc.name.should == 'Stimpson J. Cat'
197
+ @edoc.admin.should be_false
198
+ end
199
+ end
@@ -0,0 +1,1003 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Querying" do
4
+ let(:document) {
5
+ Doc do
6
+ key :first_name, String
7
+ key :last_name, String
8
+ key :age, Integer
9
+ key :date, Date
10
+ end
11
+ }
12
+
13
+ context ".query" do
14
+ let(:query) { document.query }
15
+
16
+ it "should set model to self" do
17
+ query.model.should == document
18
+ end
19
+
20
+ it "should always return new instance" do
21
+ document.query.should_not equal(query)
22
+ end
23
+
24
+ it "should apply options" do
25
+ document.query(:foo => 'bar')[:foo].should == 'bar'
26
+ end
27
+ end
28
+
29
+ context ".criteria_hash" do
30
+ let(:hash) { document.criteria_hash }
31
+
32
+ it "should set object id keys on hash" do
33
+ hash.object_ids.should == [:_id]
34
+ end
35
+
36
+ it "should always return new instance" do
37
+ document.criteria_hash.should_not equal(hash)
38
+ end
39
+
40
+ it "should apply provided criteria" do
41
+ document.criteria_hash(:foo => 'bar')[:foo].should == 'bar'
42
+ end
43
+ end
44
+
45
+ context ".create (single document)" do
46
+ let!(:doc) { document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'}) }
47
+
48
+ it "should create a document in correct collection" do
49
+ document.count.should == 1
50
+ end
51
+
52
+ it "should automatically set id" do
53
+ doc.id.should be_instance_of(BSON::ObjectId)
54
+ doc._id.should be_instance_of(BSON::ObjectId)
55
+ end
56
+
57
+ it "should no longer be new?" do
58
+ doc.new?.should be_false
59
+ end
60
+
61
+ it "should return instance of document" do
62
+ doc.should be_instance_of(document)
63
+ doc.first_name.should == 'John'
64
+ doc.last_name.should == 'Nunemaker'
65
+ doc.age.should == 27
66
+ end
67
+
68
+ it "should not fail if no attributes provided" do
69
+ document = Doc()
70
+ lambda { document.create }.should change { document.count }.by(1)
71
+ end
72
+ end
73
+
74
+ context ".create (multiple documents)" do
75
+ before do
76
+ @docs = document.create([
77
+ {:first_name => 'John', :last_name => 'Nunemaker', :age => '27'},
78
+ {:first_name => 'Steve', :last_name => 'Smith', :age => '28'},
79
+ ])
80
+ end
81
+
82
+ it "should create multiple documents" do
83
+ document.count.should == 2
84
+ end
85
+
86
+ it "should return an array of doc instances" do
87
+ @docs.map do |doc|
88
+ doc.should be_instance_of(document)
89
+ end
90
+ end
91
+ end
92
+
93
+ context ".update (single document)" do
94
+ before do
95
+ doc = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
96
+ @doc = document.update(doc._id, {:age => 40})
97
+ end
98
+
99
+ it "should update attributes provided" do
100
+ @doc.age.should == 40
101
+ end
102
+
103
+ it "should not update existing attributes that were not set to update" do
104
+ @doc.first_name.should == 'John'
105
+ @doc.last_name.should == 'Nunemaker'
106
+ end
107
+
108
+ it "should not create new document" do
109
+ document.count.should == 1
110
+ end
111
+
112
+ it "should raise error if not provided id" do
113
+ doc = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
114
+ lambda { document.update }.should raise_error(ArgumentError)
115
+ end
116
+
117
+ it "should raise error if not provided attributes" do
118
+ doc = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
119
+ lambda { document.update(doc._id) }.should raise_error(ArgumentError)
120
+ lambda { document.update(doc._id, [1]) }.should raise_error(ArgumentError)
121
+ end
122
+ end
123
+
124
+ context ".update (multiple documents)" do
125
+ before do
126
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
127
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
128
+
129
+ @docs = document.update({
130
+ @doc1._id => {:age => 30},
131
+ @doc2._id => {:age => 30},
132
+ })
133
+ end
134
+
135
+ it "should not create any new documents" do
136
+ document.count.should == 2
137
+ end
138
+
139
+ it "should should return an array of doc instances" do
140
+ @docs.map do |doc|
141
+ doc.should be_instance_of(document)
142
+ end
143
+ end
144
+
145
+ it "should update the documents" do
146
+ document.find(@doc1._id).age.should == 30
147
+ document.find(@doc2._id).age.should == 30
148
+ end
149
+
150
+ it "should raise error if not a hash" do
151
+ lambda { document.update([1, 2]) }.should raise_error(ArgumentError)
152
+ end
153
+ end
154
+
155
+ context ".find" do
156
+ before do
157
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
158
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
159
+ @doc3 = document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
160
+ end
161
+
162
+ it "should return nil if nothing provided for find" do
163
+ document.find.should be_nil
164
+ end
165
+
166
+ it "should raise document not found if nothing provided for find!" do
167
+ expect { document.find! }.to raise_error(MongoMapper::DocumentNotFound)
168
+ end
169
+
170
+ context "(with a single id)" do
171
+ it "should work" do
172
+ document.find(@doc1._id).should == @doc1
173
+ end
174
+
175
+ it "should return nil if document not found with find" do
176
+ document.find(123).should be_nil
177
+ end
178
+
179
+ it "should raise error if document not found with find!" do
180
+ expect { document.find!(123) }.to raise_error(MongoMapper::DocumentNotFound)
181
+ end
182
+ end
183
+
184
+ context "(with multiple id's)" do
185
+ it "should work as arguments" do
186
+ document.find(@doc1._id, @doc2._id).should == [@doc1, @doc2]
187
+ end
188
+
189
+ it "should work as arguments with string ids" do
190
+ document.find(@doc1._id.to_s, @doc2._id.to_s).should == [@doc1, @doc2]
191
+ end
192
+
193
+ it "should work as array" do
194
+ document.find([@doc1._id, @doc2._id]).should == [@doc1, @doc2]
195
+ end
196
+
197
+ it "should work as array with string ids" do
198
+ document.find([@doc1._id.to_s, @doc2._id.to_s]).should == [@doc1, @doc2]
199
+ end
200
+
201
+ it "should compact not found when using find" do
202
+ document.find(@doc1._id, BSON::ObjectId.new.to_s).should == [@doc1]
203
+ end
204
+
205
+ it "should raise error if not all found when using find!" do
206
+ expect {
207
+ document.find!(@doc1._id, BSON::ObjectId.new.to_s)
208
+ }.to raise_error(MongoMapper::DocumentNotFound)
209
+ end
210
+
211
+ it "should raise error if not all found when using find!" do
212
+ expect {
213
+ document.find!([@doc1._id, BSON::ObjectId.new.to_s])
214
+ }.to raise_error(MongoMapper::DocumentNotFound)
215
+ end
216
+
217
+ it "should return array if array with one element" do
218
+ document.find([@doc1._id]).should == [@doc1]
219
+ end
220
+ end
221
+
222
+ it "should be able to find using condition auto-detection" do
223
+ document.first(:first_name => 'John').should == @doc1
224
+ document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
225
+ end
226
+
227
+ context "#all" do
228
+ it "should find all documents with options" do
229
+ document.all(:order => 'first_name').should == [@doc1, @doc3, @doc2]
230
+ document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
231
+ end
232
+ end
233
+
234
+ context "#first" do
235
+ it "should find first document with options" do
236
+ document.first(:order => 'first_name').should == @doc1
237
+ document.first(:age => 28).should == @doc2
238
+ end
239
+ end
240
+
241
+ context "#last" do
242
+ it "should find last document with options" do
243
+ document.last(:order => 'age').should == @doc2
244
+ document.last(:order => 'age', :age => 28).should == @doc2
245
+ end
246
+ end
247
+
248
+ context "#find_each" do
249
+ it "should yield all documents found based on options" do
250
+ yield_documents = []
251
+ document.find_each(:order => "first_name") {|doc| yield_documents << doc }
252
+ yield_documents.should == [@doc1, @doc3, @doc2]
253
+
254
+ yield_documents = []
255
+ document.find_each(:last_name => 'Nunemaker', :order => 'age desc') {|doc| yield_documents << doc }
256
+ yield_documents.should == [@doc1, @doc3]
257
+ end
258
+ end
259
+ end # finding documents
260
+
261
+ context ".find_by_id" do
262
+ before do
263
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
264
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
265
+ end
266
+
267
+ it "should be able to find by id" do
268
+ document.find_by_id(@doc1._id).should == @doc1
269
+ document.find_by_id(@doc2._id).should == @doc2
270
+ end
271
+
272
+ it "should return nil if document not found" do
273
+ document.find_by_id(1234).should be_nil
274
+ end
275
+ end
276
+
277
+ context ".first_or_create" do
278
+ it "should find if exists" do
279
+ created = document.create(:first_name => 'John', :last_name => 'Nunemaker')
280
+ lambda {
281
+ found = document.first_or_create(:first_name => 'John', :last_name => 'Nunemaker')
282
+ found.should == created
283
+ }.should_not change { document.count }
284
+ end
285
+
286
+ it "should create if not found" do
287
+ lambda {
288
+ created = document.first_or_create(:first_name => 'John', :last_name => 'Nunemaker')
289
+ created.first_name.should == 'John'
290
+ created.last_name.should == 'Nunemaker'
291
+ }.should change { document.count }.by(1)
292
+ end
293
+
294
+ it "should disregard non-keys when creating, but use them in the query" do
295
+ expect {
296
+ document.create(:first_name => 'John', :age => 9)
297
+ lambda {
298
+ document.first_or_create(:first_name => 'John', :age.gt => 10).first_name.should == 'John'
299
+ }.should change { document.count }.by(1)
300
+ }.to_not raise_error
301
+ end
302
+ end
303
+
304
+ context ".first_or_new" do
305
+ it "should find if exists" do
306
+ created = document.create(:first_name => 'John', :last_name => 'Nunemaker')
307
+ lambda {
308
+ found = document.first_or_new(:first_name => 'John', :last_name => 'Nunemaker')
309
+ found.should == created
310
+ }.should_not change { document.count }
311
+ end
312
+
313
+ it "should initialize if not found" do
314
+ lambda {
315
+ created = document.first_or_new(:first_name => 'John', :last_name => 'Nunemaker')
316
+ created.first_name.should == 'John'
317
+ created.last_name.should == 'Nunemaker'
318
+ created.should be_new
319
+ }.should_not change { document.count }
320
+ end
321
+
322
+ it "should disregard non-keys when initializing, but use them in the query" do
323
+ expect {
324
+ document.create(:first_name => 'John', :age => 9)
325
+ document.first_or_new(:first_name => 'John', :age.gt => 10).first_name.should == 'John'
326
+ }.to_not raise_error
327
+ end
328
+ end
329
+
330
+ context ".delete (single document)" do
331
+ before do
332
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
333
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
334
+ document.delete(@doc1._id)
335
+ end
336
+
337
+ it "should remove document from collection" do
338
+ document.count.should == 1
339
+ end
340
+
341
+ it "should not remove other documents" do
342
+ document.find(@doc2._id).should_not be(nil)
343
+ end
344
+ end
345
+
346
+ context ".delete (multiple documents)" do
347
+ it "should work with multiple arguments" do
348
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
349
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
350
+ @doc3 = document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
351
+ document.delete(@doc1._id, @doc2._id)
352
+
353
+ document.count.should == 1
354
+ end
355
+
356
+ it "should work with array as argument" do
357
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
358
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
359
+ @doc3 = document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
360
+ document.delete([@doc1._id, @doc2._id])
361
+
362
+ document.count.should == 1
363
+ end
364
+ end
365
+
366
+ context ".delete_all" do
367
+ before do
368
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
369
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
370
+ @doc3 = document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
371
+ end
372
+
373
+ it "should remove all documents when given no conditions" do
374
+ document.delete_all
375
+ document.count.should == 0
376
+ end
377
+
378
+ it "should only remove matching documents when given conditions" do
379
+ document.delete_all({:first_name => 'John'})
380
+ document.count.should == 2
381
+ end
382
+
383
+ it "should convert the conditions to mongo criteria" do
384
+ document.delete_all(:age => [26, 27])
385
+ document.count.should == 1
386
+ end
387
+ end
388
+
389
+ context ".destroy (single document)" do
390
+ before do
391
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
392
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
393
+ document.destroy(@doc1._id)
394
+ end
395
+
396
+ it "should remove document from collection" do
397
+ document.count.should == 1
398
+ end
399
+
400
+ it "should not remove other documents" do
401
+ document.find(@doc2._id).should_not be(nil)
402
+ end
403
+ end
404
+
405
+ context ".destroy (multiple documents)" do
406
+ it "should work with multiple arguments" do
407
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
408
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
409
+ @doc3 = document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
410
+ document.destroy(@doc1._id, @doc2._id)
411
+
412
+ document.count.should == 1
413
+ end
414
+
415
+ it "should work with array as argument" do
416
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
417
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
418
+ @doc3 = document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
419
+ document.destroy([@doc1._id, @doc2._id])
420
+
421
+ document.count.should == 1
422
+ end
423
+ end
424
+
425
+ context ".destroy_all" do
426
+ before do
427
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
428
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
429
+ @doc3 = document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
430
+ end
431
+
432
+ it "should remove all documents when given no conditions" do
433
+ document.destroy_all
434
+ document.count.should == 0
435
+ end
436
+
437
+ it "should only remove matching documents when given conditions" do
438
+ document.destroy_all(:first_name => 'John')
439
+ document.count.should == 2
440
+ document.destroy_all(:age => 26)
441
+ document.count.should == 1
442
+ end
443
+
444
+ it "should convert the conditions to mongo criteria" do
445
+ document.destroy_all(:age => [26, 27])
446
+ document.count.should == 1
447
+ end
448
+ end
449
+
450
+ context ".count" do
451
+ before do
452
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
453
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
454
+ @doc3 = document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
455
+ end
456
+
457
+ it "should count all with no arguments" do
458
+ document.count.should == 3
459
+ end
460
+
461
+ it "should return 0 if there are no documents in the collection" do
462
+ document.delete_all
463
+ document.count.should == 0
464
+ end
465
+
466
+ it "should return 0 if the collection does not exist" do
467
+ klass = Doc do
468
+ set_collection_name 'foobarbazwickdoesnotexist'
469
+ end
470
+
471
+ klass.count.should == 0
472
+ end
473
+
474
+ it "should return count for matching documents if conditions provided" do
475
+ document.count(:age => 27).should == 1
476
+ end
477
+
478
+ it "should convert the conditions to mongo criteria" do
479
+ document.count(:age => [26, 27]).should == 2
480
+ end
481
+ end
482
+
483
+ context ".size" do
484
+ it "should return 0 if no documents" do
485
+ document.count.should == 0
486
+ end
487
+
488
+ it "should return the number of documents" do
489
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
490
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
491
+ @doc3 = document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
492
+ document.count.should == 3
493
+ end
494
+ end
495
+
496
+ context ".empty?" do
497
+ it "should be true if no documents" do
498
+ document.empty?.should be_true
499
+ end
500
+
501
+ it "should be false if documents present" do
502
+ @doc = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
503
+ document.empty?.should be_false
504
+ end
505
+ end
506
+
507
+ context ".exists?" do
508
+ before do
509
+ @doc = document.create(:first_name => "James", :age => 27)
510
+ end
511
+
512
+ it "should be true when at least one document exists" do
513
+ document.exists?.should == true
514
+ end
515
+
516
+ it "should be false when no documents exist" do
517
+ @doc.destroy
518
+ document.exists?.should == false
519
+ end
520
+
521
+ it "should be true when at least one document exists that matches the conditions" do
522
+ document.exists?(:first_name => "James").should == true
523
+ end
524
+
525
+ it "should be false when no documents exist with the provided conditions" do
526
+ document.exists?(:first_name => "Jean").should == false
527
+ end
528
+ end
529
+
530
+ context "to_a" do
531
+ it "should return an array" do
532
+ document.to_a.class.should == Array
533
+ end
534
+
535
+ it "should return everything" do
536
+ @doc2 = document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
537
+ @doc1 = document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
538
+ @doc3 = document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
539
+ document.to_a.size.should == 3
540
+ end
541
+ end
542
+
543
+ context ".where" do
544
+ let!(:query) { document.where(:last_name => 'Nunemaker') }
545
+ let!(:doc1) { document.create(:first_name => 'John', :last_name => 'Nunemaker', :age => '27') }
546
+ let!(:doc2) { document.create(:first_name => 'Steve', :last_name => 'Smith', :age => '28') }
547
+ let!(:doc3) { document.create(:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26') }
548
+
549
+ it "should fetch documents when kicker called" do
550
+ docs = query.all
551
+ docs.should include(doc1)
552
+ docs.should include(doc3)
553
+ docs.should_not include(doc2)
554
+ end
555
+
556
+ it "should be chainable" do
557
+ query.sort(:age).first.should == doc3
558
+ end
559
+
560
+ context "with methods from MongoMapper::Plugins::Querying" do
561
+ it "should delete" do
562
+ lambda do
563
+ document.where(:first_name => 'Steve').delete(doc1.id, doc2.id)
564
+ end.should change { document.count }.by(-1)
565
+ document.all(:order => 'first_name').should == [doc1, doc3]
566
+ end
567
+
568
+ it "should delete_all" do
569
+ lambda do
570
+ document.where(:first_name => 'Steph').delete_all(:last_name => "Nunemaker")
571
+ end.should change { document.count }.by(-1)
572
+ document.all(:order => 'first_name').should == [doc1, doc2]
573
+ end
574
+
575
+ it "should destroy" do
576
+ lambda do
577
+ document.where(:first_name => 'Steve').destroy(doc1.id, doc2.id)
578
+ end.should raise_error(MongoMapper::DocumentNotFound)
579
+ document.count.should == 3
580
+
581
+ lambda do
582
+ document.where(:last_name => 'Nunemaker').destroy(doc1.id, doc3.id)
583
+ end.should change { document.count }.by(-2)
584
+ document.all.should == [doc2]
585
+ end
586
+
587
+ it "should destroy_all" do
588
+ lambda do
589
+ document.where(:first_name => 'Steph').destroy_all(:last_name => "Nunemaker")
590
+ end.should change { document.count }.by(-1)
591
+ document.all(:order => 'first_name').should == [doc1, doc2]
592
+ end
593
+ end
594
+ end
595
+
596
+ context ".fields" do
597
+ before do
598
+ @doc1 = document.create(:first_name => 'John', :last_name => 'Nunemaker', :age => '27')
599
+ @doc2 = document.create(:first_name => 'Steve', :last_name => 'Smith', :age => '28')
600
+ @doc3 = document.create(:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26')
601
+ @query = document.fields(:age)
602
+ end
603
+
604
+ it "should fetch documents when kicker called" do
605
+ docs = @query.all
606
+ docs.should include(@doc1)
607
+ docs.should include(@doc3)
608
+ docs.should include(@doc2)
609
+ docs.each do |doc|
610
+ doc.age.should_not be_nil
611
+ doc.first_name.should be_nil # key was not loaded
612
+ doc.last_name.should be_nil # key was not loaded
613
+ end
614
+ end
615
+
616
+ it "should be chainable" do
617
+ @query.sort(:age).all.map(&:age).should == [26, 27, 28]
618
+ end
619
+ end
620
+
621
+ context ".limit" do
622
+ before do
623
+ @doc1 = document.create(:first_name => 'John', :last_name => 'Nunemaker', :age => '27')
624
+ @doc2 = document.create(:first_name => 'Steve', :last_name => 'Smith', :age => '28')
625
+ @doc3 = document.create(:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26')
626
+ @query = document.limit(2)
627
+ end
628
+
629
+ it "should fetch documents when kicker called" do
630
+ docs = @query.all
631
+ docs.size.should == 2
632
+ end
633
+
634
+ it "should be chainable" do
635
+ result = [26, 27]
636
+ @query.sort(:age).all.map(&:age).should == result
637
+ @query.count.should > result.size
638
+ end
639
+ end
640
+
641
+ context ".skip" do
642
+ before do
643
+ @doc1 = document.create(:first_name => 'John', :last_name => 'Nunemaker', :age => '27')
644
+ @doc2 = document.create(:first_name => 'Steve', :last_name => 'Smith', :age => '28')
645
+ @doc3 = document.create(:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26')
646
+ @query = document.skip(1)
647
+ end
648
+
649
+ it "should fetch documents when kicker called" do
650
+ docs = @query.all
651
+ docs.size.should == 2 # skipping 1 out of 3
652
+ end
653
+
654
+ it "should be chainable" do
655
+ result = [27, 28]
656
+ @query.sort(:age).all.map(&:age).should == result
657
+ @query.count.should > result.size
658
+ end
659
+ end
660
+
661
+ context ".sort" do
662
+ before do
663
+ @doc1 = document.create(:first_name => 'John', :last_name => 'Nunemaker', :age => '27')
664
+ @doc2 = document.create(:first_name => 'Steve', :last_name => 'Smith', :age => '28')
665
+ @doc3 = document.create(:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26')
666
+ @query = document.sort(:age)
667
+ end
668
+
669
+ it "should fetch documents when kicker called" do
670
+ @query.all.should == [@doc3, @doc1, @doc2]
671
+ end
672
+
673
+ it "should be chainable" do
674
+ result = [28]
675
+ @query.skip(2).all.map(&:age).should == result
676
+ @query.count.should > result.size
677
+ end
678
+ end
679
+
680
+ context "#update_attributes (new document)" do
681
+ before do
682
+ @doc = document.new(:first_name => 'John', :age => '27')
683
+ @doc.update_attributes(:first_name => 'Johnny', :age => 30)
684
+ end
685
+
686
+ it "should insert document into the collection" do
687
+ document.count.should == 1
688
+ end
689
+
690
+ it "should assign an id for the document" do
691
+ @doc.id.should be_instance_of(BSON::ObjectId)
692
+ end
693
+
694
+ it "should save attributes" do
695
+ @doc.first_name.should == 'Johnny'
696
+ @doc.age.should == 30
697
+ end
698
+
699
+ it "should update attributes in the database" do
700
+ doc = @doc.reload
701
+ doc.should == @doc
702
+ doc.first_name.should == 'Johnny'
703
+ doc.age.should == 30
704
+ end
705
+
706
+ it "should allow updating custom attributes" do
707
+ @doc.update_attributes(:gender => 'mALe')
708
+ @doc.reload.gender.should == 'mALe'
709
+ end
710
+ end
711
+
712
+ context "#update_attributes (existing document)" do
713
+ before do
714
+ @doc = document.create(:first_name => 'John', :age => '27')
715
+ @doc.update_attributes(:first_name => 'Johnny', :age => 30)
716
+ end
717
+
718
+ it "should not insert document into collection" do
719
+ document.count.should == 1
720
+ end
721
+
722
+ it "should update attributes" do
723
+ @doc.first_name.should == 'Johnny'
724
+ @doc.age.should == 30
725
+ end
726
+
727
+ it "should update attributes in the database" do
728
+ doc = @doc.reload
729
+ doc.first_name.should == 'Johnny'
730
+ doc.age.should == 30
731
+ end
732
+ end
733
+
734
+ context "#update_attributes (return value)" do
735
+ before do
736
+ document.key :foo, String, :required => true
737
+ end
738
+
739
+ it "should be true if document valid" do
740
+ document.new.update_attributes(:foo => 'bar').should be_true
741
+ end
742
+
743
+ it "should be false if document not valid" do
744
+ document.new.update_attributes({}).should be_false
745
+ end
746
+ end
747
+
748
+ context "#update_attribute" do
749
+ before do
750
+ @doc = document.create(:first_name => 'John', :age => '27')
751
+ end
752
+
753
+ it "should accept symbols as keys" do
754
+ @doc.update_attribute(:first_name, 'Chris').should be_true
755
+ @doc.reload.first_name.should == 'Chris'
756
+ end
757
+
758
+ it "should update the attribute" do
759
+ @doc.update_attribute('first_name', 'Chris').should be_true
760
+ @doc.reload.first_name.should == 'Chris'
761
+ end
762
+
763
+ it "should update the attribute without invoking validations" do
764
+ document.key :name, String, :required => true
765
+
766
+ @doc.should_receive(:valid?).never
767
+ @doc.update_attribute('name', '').should be_true
768
+ @doc.reload.name.should == ''
769
+ document.count.should == 1
770
+ end
771
+ end
772
+
773
+ context "#save (new document)" do
774
+ before do
775
+ @doc = document.new(:first_name => 'John', :age => '27')
776
+ @doc.save
777
+ end
778
+
779
+ it "should insert document into the collection" do
780
+ document.count.should == 1
781
+ end
782
+
783
+ it "should assign an id for the document" do
784
+ @doc.id.should be_instance_of(BSON::ObjectId)
785
+ end
786
+
787
+ it "should save attributes" do
788
+ @doc.first_name.should == 'John'
789
+ @doc.age.should == 27
790
+ end
791
+
792
+ it "should update attributes in the database" do
793
+ doc = @doc.reload
794
+ doc.should == @doc
795
+ doc.first_name.should == 'John'
796
+ doc.age.should == 27
797
+ end
798
+
799
+ it "should allow to add custom attributes to the document" do
800
+ @doc = document.new(:first_name => 'David', :age => '26', :gender => 'male', :tags => [1, "2"])
801
+ @doc.save
802
+ doc = @doc.reload
803
+ doc.gender.should == 'male'
804
+ doc.tags.should == [1, "2"]
805
+ end
806
+
807
+ it "should allow to use custom methods to assign properties" do
808
+ klass = Doc do
809
+ key :name, String
810
+
811
+ def realname=(value)
812
+ self.name = value
813
+ end
814
+ end
815
+
816
+ person = klass.new(:realname => 'David')
817
+ person.save
818
+ person.reload.name.should == 'David'
819
+ end
820
+
821
+ context "with key of type date" do
822
+ it "should save the date value as a Time object" do
823
+ doc = document.new(:first_name => 'John', :age => '27', :date => "2009-12-01")
824
+ doc.save
825
+ doc.date.should == Date.new(2009, 12, 1)
826
+ end
827
+ end
828
+ end
829
+
830
+ context "#save (existing document)" do
831
+ before do
832
+ @doc = document.create(:first_name => 'John', :age => '27')
833
+ @doc.first_name = 'Johnny'
834
+ @doc.age = 30
835
+ @doc.save
836
+ end
837
+
838
+ it "should not insert document into collection" do
839
+ document.count.should == 1
840
+ end
841
+
842
+ it "should update attributes" do
843
+ @doc.first_name.should == 'Johnny'
844
+ @doc.age.should == 30
845
+ end
846
+
847
+ it "should update attributes in the database" do
848
+ doc = @doc.reload
849
+ doc.first_name.should == 'Johnny'
850
+ doc.age.should == 30
851
+ end
852
+
853
+ it "should allow updating custom attributes" do
854
+ @doc = document.new(:first_name => 'David', :age => '26', :gender => 'male')
855
+ @doc.gender = 'Male'
856
+ @doc.save
857
+ @doc.reload.gender.should == 'Male'
858
+ end
859
+ end
860
+
861
+ context "#save (with validations off)" do
862
+ before do
863
+ document = Doc do
864
+ key :name, String, :required => true
865
+ end
866
+ end
867
+
868
+ it "should insert invalid document" do
869
+ doc = document.new
870
+ doc.should_receive(:valid?).never
871
+ doc.save(:validate => false)
872
+ document.count.should == 1
873
+ end
874
+ end
875
+
876
+ context "#save (with options)" do
877
+ before do
878
+ @document = Doc do
879
+ key :name, String
880
+ end
881
+ @document.ensure_index :name, :unique => true
882
+ end
883
+ after { drop_indexes(@document) }
884
+
885
+ it "should allow passing safe" do
886
+ @document.create(:name => 'John')
887
+ expect {
888
+ @document.new(:name => 'John').save(:safe => true)
889
+ }.to raise_error(Mongo::OperationFailure)
890
+ end
891
+
892
+ it "should raise argument error if options has unsupported key" do
893
+ expect {
894
+ @document.new.save(:foo => true)
895
+ }.to raise_error(ArgumentError)
896
+ end
897
+ end
898
+
899
+ context "#save! (with options)" do
900
+ before do
901
+ @document = Doc { key :name, String }
902
+ @document.ensure_index :name, :unique => true
903
+ end
904
+ after { drop_indexes(@document) }
905
+
906
+ it "should allow passing safe" do
907
+ @document.create(:name => 'John')
908
+ expect {
909
+ @document.new(:name => 'John').save!(:safe => true)
910
+ }.to raise_error(Mongo::OperationFailure)
911
+ end
912
+
913
+ it "should raise argument error if options has unsupported key" do
914
+ expect {
915
+ @document.new.save!(:foo => true)
916
+ }.to raise_error(ArgumentError)
917
+ end
918
+
919
+ it "should raise argument error if using validate as that would be pointless with save!" do
920
+ expect {
921
+ @document.new.save!(:validate => false)
922
+ }.to raise_error(ArgumentError)
923
+ end
924
+ end
925
+
926
+ context "#destroy" do
927
+ before do
928
+ @doc = document.create(:first_name => 'John', :age => '27')
929
+ @doc.destroy
930
+ end
931
+
932
+ it "should remove the document from the collection" do
933
+ document.count.should == 0
934
+ end
935
+ end
936
+
937
+ context "#delete" do
938
+ before do
939
+ @doc1 = document.create(:first_name => 'John', :last_name => 'Nunemaker', :age => '27')
940
+ @doc2 = document.create(:first_name => 'Steve', :last_name => 'Smith', :age => '28')
941
+
942
+ document.class_eval do
943
+ before_destroy :before_destroy_callback
944
+ after_destroy :after_destroy_callback
945
+
946
+ def history; @history ||= [] end
947
+ def before_destroy_callback; history << :after_destroy end
948
+ def after_destroy_callback; history << :after_destroy end
949
+ end
950
+
951
+ @doc1.delete
952
+ end
953
+
954
+ it "should remove document from collection" do
955
+ document.count.should == 1
956
+ end
957
+
958
+ it "should not remove other documents" do
959
+ document.find(@doc2.id).should_not be(nil)
960
+ end
961
+
962
+ it "should not call before/after destroy callbacks" do
963
+ @doc1.history.should == []
964
+ end
965
+ end
966
+
967
+ context "#new" do
968
+ it "should accept a block" do
969
+ user = document.new do |doc|
970
+ doc.first_name = "John"
971
+ end
972
+
973
+ user.first_name.should == "John"
974
+ end
975
+ end
976
+
977
+ context "#create" do
978
+ it "should accept a block" do
979
+ user = document.create do |doc|
980
+ doc.first_name = "John"
981
+ end
982
+
983
+ user.first_name.should == "John"
984
+ end
985
+ end
986
+
987
+ context "#create!" do
988
+ it "should accept a block" do
989
+ user = document.create! do |doc|
990
+ doc.first_name = "John"
991
+ end
992
+
993
+ user.first_name.should == "John"
994
+ end
995
+ end
996
+
997
+ context "#scoped" do
998
+ it "should return a Query" do
999
+ document.scoped.should be_a MongoMapper::Plugins::Querying::DecoratedPluckyQuery
1000
+ document.scoped.criteria_hash.should be_empty
1001
+ end
1002
+ end
1003
+ end