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,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Indexing" do
4
+ before do
5
+ @document = Doc do
6
+ key :first_name, String
7
+ key :last_name, String
8
+ key :age, Integer
9
+ key :date, Date
10
+ end
11
+ end
12
+ after { drop_indexes(@document) }
13
+
14
+ [:create_index, :ensure_index, :drop_index, :drop_indexes].each do |method|
15
+ it "should delegate #{method} to collection" do
16
+ @document.stub(:collection).and_return(double(:name => :foo))
17
+ @document.collection.should_receive(method).with(:arg)
18
+ @document.send(method, :arg)
19
+ end
20
+ end
21
+
22
+ it "should allow creating index for a key" do
23
+ @document.ensure_index :first_name
24
+ @document.should have_index('first_name_1')
25
+ end
26
+
27
+ it "should allow creating unique index for a key" do
28
+ @document.ensure_index :first_name, :unique => true
29
+ @document.should have_index('first_name_1')
30
+ end
31
+
32
+ it "should allow creating index on multiple keys" do
33
+ @document.ensure_index [[:first_name, 1], [:last_name, -1]]
34
+
35
+ # order is different for different versions of ruby so instead of
36
+ # just checking have_index('first_name_1_last_name_-1') I'm checking
37
+ # the values of the indexes to make sure the index creation was successful
38
+ @document.collection.index_information.detect do |index|
39
+ keys = index[0]
40
+ keys.include?('first_name_1') && keys.include?('last_name_-1')
41
+ end.should_not be_nil
42
+ end
43
+
44
+ it "should work with :index shortcut when defining key" do
45
+ silence_stderr { @document.key :father, String, :index => true }
46
+ @document.should have_index('father_1')
47
+ end
48
+ end
@@ -0,0 +1,224 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Keys" do
4
+ it "should not have a disparity between the ivar and accessor" do
5
+ doc = Doc do
6
+ key :foo, String
7
+
8
+ def modify_foo
9
+ @foo = :baz
10
+ end
11
+
12
+ def get_foo
13
+ @foo
14
+ end
15
+ end
16
+
17
+ instance = doc.new(:foo => "bar")
18
+ instance.get_foo.should == instance.foo
19
+
20
+ instance.foo = :bing
21
+ instance.get_foo.should == instance.foo
22
+
23
+ instance.modify_foo
24
+ instance.get_foo.should == instance.foo
25
+ end
26
+
27
+ it "should not bomb if a key is written before Keys#initialize gets to get called" do
28
+ doc = Class.new do
29
+ include MongoMapper::Document
30
+
31
+ def initialize
32
+ self.class.key :something, String
33
+ self.something = :other_thing
34
+ super
35
+ end
36
+ end
37
+
38
+ expect { doc.new }.to_not raise_error
39
+ end
40
+
41
+ it "should not bomb if a key is read before Keys#initialize gets to get called" do
42
+ doc = Class.new do
43
+ include MongoMapper::Document
44
+
45
+ def initialize
46
+ self.class.key :something, String
47
+ self.something
48
+ super
49
+ end
50
+ end
51
+
52
+ expect { doc.new }.to_not raise_error
53
+ end
54
+
55
+
56
+ context "key segmenting" do
57
+ let(:doc) {
58
+ Doc {
59
+ key :defined
60
+ }
61
+ }
62
+
63
+ before do
64
+ doc.collection.insert(:dynamic => "foo")
65
+ doc.first
66
+ end
67
+
68
+ describe "#dynamic_keys" do
69
+ it "should find dynamic keys" do
70
+ doc.dynamic_keys.keys.should == ["dynamic"]
71
+ end
72
+ end
73
+
74
+ describe "#defined_keys" do
75
+ it "should find defined keys" do
76
+ doc.defined_keys.keys.should =~ ["_id", "defined"]
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "with invalid names" do
82
+ it "should warn when key names start with an uppercase letter" do
83
+ doc = Doc {}
84
+ Kernel.should_receive(:warn).once.with(/may not start with uppercase letters/)
85
+ doc.class_eval do
86
+ key :NotConstant
87
+ end
88
+ end
89
+
90
+ it "should handle keys that start with uppercase letters by translating their first letter to lowercase" do
91
+ doc = Doc {}
92
+ Kernel.stub(:warn)
93
+ doc.class_eval do
94
+ key :NotConstant
95
+ end
96
+ doc.collection.insert("NotConstant" => "Just data!")
97
+ doc.first.notConstant.should == "Just data!"
98
+ end
99
+
100
+ it "should not create accessors for bad keys" do
101
+ doc = Doc {}
102
+ doc.should_not_receive(:create_accessors_for)
103
+ doc.class_eval do
104
+ key :"bad-name", :__dynamic => true
105
+ end
106
+ expect { doc.new.method(:"bad-name") }.to raise_error(NameError)
107
+ end
108
+
109
+ it "should create accessors for good keys" do
110
+ doc = Doc {
111
+ key :good_name
112
+ }
113
+ doc.new.good_name.should be_nil
114
+ expect { doc.new.method("good_name") }.to_not raise_error
115
+ end
116
+ end
117
+
118
+ it "should handle loading dynamic fields from the database that have bad names" do
119
+ doc = Doc {}
120
+ doc.collection.insert("foo-bar" => "baz-bin")
121
+
122
+ doc.first["foo-bar"].should == "baz-bin"
123
+ end
124
+
125
+ describe "with aliases" do
126
+ AliasedKeyModel = Doc do
127
+ key :foo, :abbr => :f
128
+ key :with_underscores, :alias => "with-hyphens"
129
+ key :field_name, :field_name => "alternate_field_name"
130
+ key :bar
131
+ end
132
+
133
+ before { AliasedKeyModel.collection.drop }
134
+
135
+ context "standard key operations" do
136
+ before do
137
+ AliasedKeyModel.create(:foo => "whee!", :bar => "whoo!")
138
+ end
139
+
140
+ it "should serialize with aliased keys" do
141
+ AliasedKeyModel.collection.find_one.keys.should =~ %w(_id f bar)
142
+
143
+ AliasedKeyModel.first.tap do |d|
144
+ d.foo.should == "whee!"
145
+ d.bar.should == "whoo!"
146
+ end
147
+ end
148
+
149
+ it "should permit querying via aliases" do
150
+ AliasedKeyModel.where(AliasedKeyModel.abbr(:f) => "whee!").first.foo.should == "whee!"
151
+ end
152
+
153
+ it "should serialize to JSON with full keys" do
154
+ AliasedKeyModel.first.as_json.tap do |json|
155
+ json.should have_key "foo"
156
+ json.should_not have_key "f"
157
+ end
158
+ end
159
+ end
160
+
161
+ context "given field which are not valid Ruby method names" do
162
+ before { AliasedKeyModel.create(:with_underscores => "foobar") }
163
+ it "should work" do
164
+ AliasedKeyModel.first.with_underscores.should == "foobar"
165
+ AliasedKeyModel.collection.find_one["with-hyphens"].should == "foobar"
166
+ end
167
+ end
168
+
169
+ context "given a field aliased with :field_name" do
170
+ before { AliasedKeyModel.create(:field_name => "foobar") }
171
+ it "should work" do
172
+ AliasedKeyModel.first.field_name.should == "foobar"
173
+ AliasedKeyModel.collection.find_one["alternate_field_name"].should == "foobar"
174
+ end
175
+ end
176
+
177
+ context "associations" do
178
+ AssociatedKeyWithAlias = Doc do
179
+ set_collection_name "associated_documents"
180
+ key :name, String, :abbr => :n
181
+ key :association_id, ObjectId, :abbr => :aid
182
+ end
183
+
184
+ OwnerDocWithKeyAliases = Doc do
185
+ set_collection_name "owner_documents"
186
+ key :name, String, :abbr => :n
187
+ many :associated_documents, :class_name => "AssociatedKeyWithAlias", :foreign_key => AssociatedKeyWithAlias.abbr(:association_id)
188
+ many :other_documents, :class_name => "EmbeddedDocWithAliases"
189
+ end
190
+
191
+ EmbeddedDocWithAliases = EDoc do
192
+ key :embedded_name, String, :abbr => :en
193
+ end
194
+
195
+ before do
196
+ AssociatedKeyWithAlias.collection.drop
197
+ OwnerDocWithKeyAliases.collection.drop
198
+ end
199
+
200
+ it "should work" do
201
+ owner = OwnerDocWithKeyAliases.create(:name => "Big Boss")
202
+
203
+ associated_documents = 3.times.map {|i| AssociatedKeyWithAlias.new(:name => "Associated Record #{i}") }
204
+ owner.associated_documents = associated_documents
205
+ owner.save
206
+
207
+ owner.reload
208
+ owner.associated_documents.to_a.should =~ associated_documents.to_a
209
+
210
+ AssociatedKeyWithAlias.collection.find_one.keys.should =~ %w(_id n aid)
211
+ end
212
+
213
+ it "should work with embedded documents" do
214
+ owner = OwnerDocWithKeyAliases.create(:name => "Big Boss")
215
+ owner.other_documents << EmbeddedDocWithAliases.new(:embedded_name => "Underling")
216
+ owner.save
217
+
218
+ owner.reload
219
+ owner.other_documents[0].embedded_name.should == "Underling"
220
+ owner.collection.find_one["other_documents"][0]["en"].should == "Underling"
221
+ end
222
+ end
223
+ end
224
+ end
@@ -1,18 +1,18 @@
1
- require 'test_helper'
1
+ require 'spec_helper'
2
2
 
3
- class LoggerTest < Test::Unit::TestCase
3
+ describe "Logger" do
4
4
  context "with connection that has logger" do
5
- setup do
5
+ before do
6
6
  @output = StringIO.new
7
7
  @logger = Logger.new(@output)
8
- MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017, :logger => @logger)
8
+ MongoMapper.connection = Mongo::MongoClient.new('127.0.0.1', 27017, :logger => @logger)
9
9
  end
10
10
 
11
- should "be able to get access to that logger" do
11
+ it "should be able to get access to that logger" do
12
12
  MongoMapper.logger.should == @logger
13
13
  end
14
14
 
15
- should "be able to log messages" do
15
+ it "should be able to log messages" do
16
16
  MongoMapper.logger.debug 'testing'
17
17
  @output.string.include?('testing').should be_true
18
18
  end
@@ -0,0 +1,550 @@
1
+ require 'spec_helper'
2
+
3
+ module Modifiers
4
+ describe "Modifiers" do
5
+ let(:page_class_with_compound_key) {
6
+ Doc do
7
+ key :_id, BSON::OrderedHash, :default => lambda { BSON::OrderedHash['n', 42, 'i', BSON::ObjectId.new] }
8
+ key :title, String
9
+ key :day_count, Integer, :default => 0
10
+ key :week_count, Integer, :default => 0
11
+ key :month_count, Integer, :default => 0
12
+ key :tags, Array
13
+ end
14
+ }
15
+
16
+ let(:page_class_with_standard_key) {
17
+ Doc do
18
+ key :title, String
19
+ key :day_count, Integer, :default => 0
20
+ key :week_count, Integer, :default => 0
21
+ key :month_count, Integer, :default => 0
22
+ key :tags, Array
23
+ end
24
+ }
25
+
26
+ def assert_page_counts(page, day_count, week_count, month_count)
27
+ doc = page.collection.find_one({:_id => page.id})
28
+ doc.should be_present, "Could not find document"
29
+ doc.fetch('day_count').should == day_count
30
+ doc.fetch('week_count').should == week_count
31
+ doc.fetch('month_count').should == month_count
32
+ end
33
+
34
+ def assert_keys_removed(page, *keys)
35
+ page.class.collection.find_one({:_id => page.id}).tap do |doc|
36
+ doc.should be_present, "Could not find document"
37
+ (doc.keys & keys).should be_empty, "Expected to not have keys #{keys.inspect}, got #{(keys & doc.keys).inspect}"
38
+ end
39
+ end
40
+
41
+ context "ClassMethods" do
42
+ let!(:page_class) { page_class_with_standard_key }
43
+ let!(:page) { page_class.create(:title => 'Home') }
44
+ let!(:page2) { page_class.create(:title => 'Home') }
45
+
46
+ context "unset" do
47
+ let!(:page) { page_class.create(:title => 'Home', :tags => %w(foo bar)) }
48
+
49
+ it "should work with criteria and keys" do
50
+ page_class.unset({:title => 'Home'}, :title, :tags)
51
+ assert_keys_removed page, :title, :tags
52
+ assert_keys_removed page2, :title, :tags
53
+ end
54
+
55
+ it "should work with ids and keys" do
56
+ page_class.unset(page.id, page2.id, :title, :tags)
57
+ assert_keys_removed page, :title, :tags
58
+ assert_keys_removed page2, :title, :tags
59
+ end
60
+
61
+ context "additional options (upsert & safe)" do
62
+ it "should be able to pass upsert option" do
63
+ new_key_value = DateTime.now.to_s
64
+ page_class.unset({:title => new_key_value, :tags => %w(foo bar)}, :tags, {:upsert => true})
65
+ page_class.count(:title => new_key_value).should == 1
66
+ page_class.first(:title => new_key_value).tags.should == []
67
+ end
68
+
69
+ it "should be able to pass safe option" do
70
+ page_class.create(:title => "Better Be Safe than Sorry")
71
+
72
+ Mongo::Collection.any_instance.should_receive(:update).with(
73
+ {:title => "Better Be Safe than Sorry"},
74
+ {'$unset' => {:tags => 1}},
75
+ {:w => 1, :multi => true}
76
+ )
77
+ page_class.unset({:title => "Better Be Safe than Sorry"}, :tags, {:w => 1})
78
+ end
79
+
80
+ it "should be able to pass both safe and upsert options" do
81
+ new_key_value = DateTime.now.to_s
82
+ page_class.unset({:title => new_key_value, :tags => %w(foo bar)}, :tags, {:upsert => true, :safe => true})
83
+ page_class.count(:title => new_key_value).should == 1
84
+ page_class.first(:title => new_key_value).tags.should == []
85
+ end
86
+ end
87
+ end
88
+
89
+ context "increment" do
90
+ it "should work with criteria and modifier hashes" do
91
+ page_class.increment({:title => 'Home'}, :day_count => 1, :week_count => 2, :month_count => 3)
92
+
93
+ assert_page_counts page, 1, 2, 3
94
+ assert_page_counts page2, 1, 2, 3
95
+ end
96
+
97
+ it "should work with ids and modifier hash" do
98
+ page_class.increment(page.id, page2.id, :day_count => 1, :week_count => 2, :month_count => 3)
99
+
100
+ assert_page_counts page, 1, 2, 3
101
+ assert_page_counts page2, 1, 2, 3
102
+ end
103
+
104
+ it "should work with ids given as strings" do
105
+ page_class.increment(page.id.to_s, page2.id.to_s, :day_count => 1, :week_count => 2, :month_count => 3)
106
+
107
+ assert_page_counts page, 1, 2, 3
108
+ assert_page_counts page2, 1, 2, 3
109
+ end
110
+ end
111
+
112
+ context "decrement" do
113
+ let!(:page) { page_class.create(:title => 'Home', :day_count => 1, :week_count => 2, :month_count => 3) }
114
+ let!(:page2) { page_class.create(:title => 'Home', :day_count => 1, :week_count => 2, :month_count => 3) }
115
+
116
+ it "should work with criteria and modifier hashes" do
117
+ page_class.decrement({:title => 'Home'}, :day_count => 1, :week_count => 2, :month_count => 3)
118
+
119
+ assert_page_counts page, 0, 0, 0
120
+ assert_page_counts page2, 0, 0, 0
121
+ end
122
+
123
+ it "should work with ids and modifier hash" do
124
+ page_class.decrement(page.id, page2.id, :day_count => 1, :week_count => 2, :month_count => 3)
125
+
126
+ assert_page_counts page, 0, 0, 0
127
+ assert_page_counts page2, 0, 0, 0
128
+ end
129
+
130
+ it "should decrement with positive or negative numbers" do
131
+ page_class.decrement(page.id, page2.id, :day_count => -1, :week_count => 2, :month_count => -3)
132
+
133
+ assert_page_counts page, 0, 0, 0
134
+ assert_page_counts page2, 0, 0, 0
135
+ end
136
+
137
+ it "should work with ids given as strings" do
138
+ page_class.decrement(page.id.to_s, page2.id.to_s, :day_count => -1, :week_count => 2, :month_count => -3)
139
+
140
+ assert_page_counts page, 0, 0, 0
141
+ assert_page_counts page2, 0, 0, 0
142
+ end
143
+ end
144
+
145
+ context "set" do
146
+ it "should work with criteria and modifier hashes" do
147
+ page_class.set({:title => 'Home'}, :title => 'Home Revised')
148
+
149
+ page.reload
150
+ page.title.should == 'Home Revised'
151
+
152
+ page2.reload
153
+ page2.title.should == 'Home Revised'
154
+ end
155
+
156
+ it "should work with ids and modifier hash" do
157
+ page_class.set(page.id, page2.id, :title => 'Home Revised')
158
+
159
+ page.reload
160
+ page.title.should == 'Home Revised'
161
+
162
+ page2.reload
163
+ page2.title.should == 'Home Revised'
164
+ end
165
+
166
+ it "should typecast values before querying" do
167
+ page_class.key :tags, Set
168
+
169
+ expect {
170
+ page_class.set(page.id, :tags => ['foo', 'bar'].to_set)
171
+ page.reload
172
+ page.tags.should == Set.new(['foo', 'bar'])
173
+ }.to_not raise_error
174
+ end
175
+
176
+ it "should not typecast keys that are not defined in document" do
177
+ expect {
178
+ page_class.set(page.id, :colors => ['red', 'green'].to_set)
179
+ }.to raise_error(BSON::InvalidDocument)
180
+ end
181
+
182
+ it "should set keys that are not defined in document" do
183
+ page_class.set(page.id, :colors => %w[red green])
184
+ page.reload
185
+ page[:colors].should == %w[red green]
186
+ end
187
+
188
+ context "additional options (upsert & safe)" do
189
+ it "should be able to pass upsert option" do
190
+ new_key_value = DateTime.now.to_s
191
+ page_class.set({:title => new_key_value}, {:day_count => 1}, {:upsert => true})
192
+ page_class.count(:title => new_key_value).should == 1
193
+ page_class.first(:title => new_key_value).day_count.should == 1
194
+ end
195
+
196
+ it "should be able to pass safe option" do
197
+ page_class.create(:title => "Better Be Safe than Sorry")
198
+
199
+ Mongo::Collection.any_instance.should_receive(:update).with(
200
+ {:title => "Better Be Safe than Sorry"},
201
+ {'$set' => {:title => "I like safety."}},
202
+ {:w => 1, :multi => true}
203
+ )
204
+ page_class.set({:title => "Better Be Safe than Sorry"}, {:title => "I like safety."}, {:safe => true})
205
+ end
206
+
207
+ it "should be able to pass both safe and upsert options" do
208
+ new_key_value = DateTime.now.to_s
209
+ page_class.set({:title => new_key_value}, {:day_count => 1}, {:upsert => true, :safe => true})
210
+ page_class.count(:title => new_key_value).should == 1
211
+ page_class.first(:title => new_key_value).day_count.should == 1
212
+ end
213
+ end
214
+ end
215
+
216
+ context "push" do
217
+ it "should work with criteria and modifier hashes" do
218
+ page_class.push({:title => 'Home'}, :tags => 'foo')
219
+
220
+ page.reload
221
+ page.tags.should == %w(foo)
222
+
223
+ page2.reload
224
+ page2.tags.should == %w(foo)
225
+ end
226
+
227
+ it "should work with ids and modifier hash" do
228
+ page_class.push(page.id, page2.id, :tags => 'foo')
229
+
230
+ page.reload
231
+ page.tags.should == %w(foo)
232
+
233
+ page2.reload
234
+ page2.tags.should == %w(foo)
235
+ end
236
+ end
237
+
238
+ context "push_all" do
239
+ let(:tags) { %w(foo bar) }
240
+
241
+ it "should work with criteria and modifier hashes" do
242
+ page_class.push_all({:title => 'Home'}, :tags => tags)
243
+
244
+ page.reload
245
+ page.tags.should == tags
246
+
247
+ page2.reload
248
+ page2.tags.should == tags
249
+ end
250
+
251
+ it "should work with ids and modifier hash" do
252
+ page_class.push_all(page.id, page2.id, :tags => tags)
253
+
254
+ page.reload
255
+ page.tags.should == tags
256
+
257
+ page2.reload
258
+ page2.tags.should == tags
259
+ end
260
+ end
261
+
262
+ context "pull" do
263
+ let(:page) { page_class.create(:title => 'Home', :tags => %w(foo bar)) }
264
+ let(:page2) { page_class.create(:title => 'Home', :tags => %w(foo bar)) }
265
+
266
+ it "should work with criteria and modifier hashes" do
267
+ page_class.pull({:title => 'Home'}, :tags => 'foo')
268
+
269
+ page.reload
270
+ page.tags.should == %w(bar)
271
+
272
+ page2.reload
273
+ page2.tags.should == %w(bar)
274
+ end
275
+
276
+ it "should be able to pull with ids and modifier hash" do
277
+ page_class.pull(page.id, page2.id, :tags => 'foo')
278
+
279
+ page.reload
280
+ page.tags.should == %w(bar)
281
+
282
+ page2.reload
283
+ page2.tags.should == %w(bar)
284
+ end
285
+ end
286
+
287
+ context "pull_all" do
288
+ let(:page) { page_class.create(:title => 'Home', :tags => %w(foo bar baz)) }
289
+ let(:page2) { page_class.create(:title => 'Home', :tags => %w(foo bar baz)) }
290
+
291
+ it "should work with criteria and modifier hashes" do
292
+ page_class.pull_all({:title => 'Home'}, :tags => %w(foo bar))
293
+
294
+ page.reload
295
+ page.tags.should == %w(baz)
296
+
297
+ page2.reload
298
+ page2.tags.should == %w(baz)
299
+ end
300
+
301
+ it "should work with ids and modifier hash" do
302
+ page_class.pull_all(page.id, page2.id, :tags => %w(foo bar))
303
+
304
+ page.reload
305
+ page.tags.should == %w(baz)
306
+
307
+ page2.reload
308
+ page2.tags.should == %w(baz)
309
+ end
310
+ end
311
+
312
+ context "add_to_set" do
313
+ let(:page) { page_class.create(:title => 'Home', :tags => 'foo') }
314
+
315
+ it "should be able to add to set with criteria and modifier hash" do
316
+ page_class.add_to_set({:title => 'Home'}, :tags => 'foo')
317
+
318
+ page.reload
319
+ page.tags.should == %w(foo)
320
+
321
+ page2.reload
322
+ page2.tags.should == %w(foo)
323
+ end
324
+
325
+ it "should be able to add to set with ids and modifier hash" do
326
+ page_class.add_to_set(page.id, page2.id, :tags => 'foo')
327
+
328
+ page.reload
329
+ page.tags.should == %w(foo)
330
+
331
+ page2.reload
332
+ page2.tags.should == %w(foo)
333
+ end
334
+ end
335
+
336
+ context "push_uniq" do
337
+ let(:page) { page_class.create(:title => 'Home', :tags => 'foo') }
338
+
339
+ it "should be able to push uniq with criteria and modifier hash" do
340
+ page_class.push_uniq({:title => 'Home'}, :tags => 'foo')
341
+
342
+ page.reload
343
+ page.tags.should == %w(foo)
344
+
345
+ page2.reload
346
+ page2.tags.should == %w(foo)
347
+ end
348
+
349
+ it "should be able to push uniq with ids and modifier hash" do
350
+ page_class.push_uniq(page.id, page2.id, :tags => 'foo')
351
+
352
+ page.reload
353
+ page.tags.should == %w(foo)
354
+
355
+ page2.reload
356
+ page2.tags.should == %w(foo)
357
+ end
358
+ end
359
+
360
+ context "pop" do
361
+ let(:page) { page_class.create(:title => 'Home', :tags => %w(foo bar)) }
362
+
363
+ it "should be able to remove the last element the array" do
364
+ page_class.pop(page.id, :tags => 1)
365
+ page.reload
366
+ page.tags.should == %w(foo)
367
+ end
368
+
369
+ it "should be able to remove the first element of the array" do
370
+ page_class.pop(page.id, :tags => -1)
371
+ page.reload
372
+ page.tags.should == %w(bar)
373
+ end
374
+ end
375
+
376
+ context "additional options (upsert & safe)" do
377
+ it "should be able to pass upsert option" do
378
+ new_key_value = DateTime.now.to_s
379
+ page_class.increment({:title => new_key_value}, {:day_count => 1}, {:upsert => true})
380
+ page_class.count(:title => new_key_value).should == 1
381
+ page_class.first(:title => new_key_value).day_count.should == 1
382
+ end
383
+
384
+ it "should be able to pass safe option" do
385
+ page_class.create(:title => "Better Be Safe than Sorry")
386
+
387
+ # We are trying to increment a key of type string here which should fail
388
+ expect {
389
+ page_class.increment({:title => "Better Be Safe than Sorry"}, {:title => 1}, {:safe => true})
390
+ }.to raise_error(Mongo::OperationFailure)
391
+ end
392
+
393
+ it "should be able to pass both safe and upsert options" do
394
+ new_key_value = DateTime.now.to_s
395
+ page_class.increment({:title => new_key_value}, {:day_count => 1}, {:upsert => true, :safe => true})
396
+ page_class.count(:title => new_key_value).should == 1
397
+ page_class.first(:title => new_key_value).day_count.should == 1
398
+ end
399
+ end
400
+ end
401
+
402
+ context "compound keys" do
403
+ it "should create a document" do
404
+ expect {
405
+ page_class_with_compound_key.create(:title => 'Foo', :tags => %w(foo))
406
+ }.to change { page_class_with_compound_key.count }.by(1)
407
+ doc = page_class_with_compound_key.first
408
+ page_class_with_compound_key.find(doc._id).should == doc
409
+ end
410
+ end
411
+
412
+ context "instance methods" do
413
+ {
414
+ :page_class_with_standard_key => "with standard key",
415
+ :page_class_with_compound_key => "with compound key",
416
+ }.each do |klass, description|
417
+ context description do
418
+ let!(:page_class) { send(klass) }
419
+
420
+ it "should be able to unset with keys" do
421
+ page = page_class.create(:title => 'Foo', :tags => %w(foo))
422
+ page.unset(:title, :tags)
423
+ assert_keys_removed page, :title, :tags
424
+ end
425
+
426
+ it "should be able to increment with modifier hashes" do
427
+ page = page_class.create
428
+ page.increment(:day_count => 1, :week_count => 2, :month_count => 3)
429
+
430
+ assert_page_counts page, 1, 2, 3
431
+ end
432
+
433
+ it "should be able to decrement with modifier hashes" do
434
+ page = page_class.create(:day_count => 1, :week_count => 2, :month_count => 3)
435
+ page.decrement(:day_count => 1, :week_count => 2, :month_count => 3)
436
+
437
+ assert_page_counts page, 0, 0, 0
438
+ end
439
+
440
+ it "should always decrement when decrement is called whether number is positive or negative" do
441
+ page = page_class.create(:day_count => 1, :week_count => 2, :month_count => 3)
442
+ page.decrement(:day_count => -1, :week_count => 2, :month_count => -3)
443
+ assert_page_counts page, 0, 0, 0
444
+ end
445
+
446
+ it "should be able to set with modifier hashes" do
447
+ page = page_class.create(:title => 'Home')
448
+ page.set(:title => 'Home Revised')
449
+
450
+ page.reload
451
+ page.title.should == 'Home Revised'
452
+ end
453
+
454
+ it "should be able to push with modifier hashes" do
455
+ page = page_class.create
456
+ page.push(:tags => 'foo')
457
+
458
+ page.reload
459
+ page.tags.should == %w(foo)
460
+ end
461
+
462
+ it "should be able to push_all with modifier hashes" do
463
+ page = page_class.create
464
+ page.push_all(:tags => %w(foo bar))
465
+
466
+ page.reload
467
+ page.tags.should == %w(foo bar)
468
+ end
469
+
470
+ it "should be able to pull with criteria and modifier hashes" do
471
+ page = page_class.create(:tags => %w(foo bar))
472
+ page.pull(:tags => 'foo')
473
+
474
+ page.reload
475
+ page.tags.should == %w(bar)
476
+ end
477
+
478
+ it "should be able to pull_all with criteria and modifier hashes" do
479
+ page = page_class.create(:tags => %w(foo bar baz))
480
+ page.pull_all(:tags => %w(foo bar))
481
+
482
+ page.reload
483
+ page.tags.should == %w(baz)
484
+ end
485
+
486
+ it "should be able to add_to_set with criteria and modifier hash" do
487
+ page = page_class.create(:tags => 'foo')
488
+ page2 = page_class.create
489
+
490
+ page.add_to_set(:tags => 'foo')
491
+ page2.add_to_set(:tags => 'foo')
492
+
493
+ page.reload
494
+ page.tags.should == %w(foo)
495
+
496
+ page2.reload
497
+ page2.tags.should == %w(foo)
498
+ end
499
+
500
+ it "should be able to push uniq with criteria and modifier hash" do
501
+ page = page_class.create(:tags => 'foo')
502
+ page2 = page_class.create
503
+
504
+ page.push_uniq(:tags => 'foo')
505
+ page2.push_uniq(:tags => 'foo')
506
+
507
+ page.reload
508
+ page.tags.should == %w(foo)
509
+
510
+ page2.reload
511
+ page2.tags.should == %w(foo)
512
+ end
513
+
514
+ it "should be able to pop with modifier hashes" do
515
+ page = page_class.create(:tags => %w(foo bar))
516
+ page.pop(:tags => 1)
517
+
518
+ page.reload
519
+ page.tags.should == %w(foo)
520
+ end
521
+
522
+ it "should be able to pass upsert option" do
523
+ page = page_class.create(:title => "Upsert Page")
524
+ page.increment({:new_count => 1}, {:upsert => true})
525
+
526
+ page.reload
527
+ page.new_count.should == 1
528
+ end
529
+
530
+ it "should be able to pass safe option" do
531
+ page = page_class.create(:title => "Safe Page")
532
+
533
+ # We are trying to increment a key of type string here which should fail
534
+ expect {
535
+ page.increment({:title => 1}, {:safe => true})
536
+ }.to raise_error(Mongo::OperationFailure)
537
+ end
538
+
539
+ it "should be able to pass upsert and safe options" do
540
+ page = page_class.create(:title => "Upsert and Safe Page")
541
+ page.increment({:another_count => 1}, {:upsert => true, :safe => true})
542
+
543
+ page.reload
544
+ page.another_count.should == 1
545
+ end
546
+ end
547
+ end
548
+ end
549
+ end
550
+ end