mongo_mapper 0.12.0 → 0.13.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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