mongo_mapper 0.7.6 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. data/README.rdoc +4 -8
  2. data/bin/mmconsole +1 -1
  3. data/examples/keys.rb +37 -0
  4. data/examples/plugins.rb +41 -0
  5. data/examples/querying.rb +35 -0
  6. data/examples/scopes.rb +52 -0
  7. data/lib/mongo_mapper.rb +77 -97
  8. data/lib/mongo_mapper/connection.rb +83 -0
  9. data/lib/mongo_mapper/document.rb +10 -252
  10. data/lib/mongo_mapper/embedded_document.rb +7 -46
  11. data/lib/mongo_mapper/exceptions.rb +30 -0
  12. data/lib/mongo_mapper/extensions/array.rb +19 -0
  13. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  14. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  15. data/lib/mongo_mapper/extensions/date.rb +25 -0
  16. data/lib/mongo_mapper/extensions/float.rb +14 -0
  17. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  18. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  19. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  20. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  21. data/lib/mongo_mapper/extensions/object.rb +27 -0
  22. data/lib/mongo_mapper/extensions/object_id.rb +30 -0
  23. data/lib/mongo_mapper/extensions/set.rb +20 -0
  24. data/lib/mongo_mapper/extensions/string.rb +18 -0
  25. data/lib/mongo_mapper/extensions/time.rb +29 -0
  26. data/lib/mongo_mapper/plugins.rb +1 -21
  27. data/lib/mongo_mapper/plugins/accessible.rb +44 -0
  28. data/lib/mongo_mapper/plugins/associations.rb +7 -24
  29. data/lib/mongo_mapper/plugins/associations/base.rb +1 -0
  30. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +5 -6
  31. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +5 -6
  32. data/lib/mongo_mapper/plugins/associations/collection.rb +1 -0
  33. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +2 -1
  34. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +22 -39
  35. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +4 -4
  36. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +22 -23
  37. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +1 -0
  38. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +1 -0
  39. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +1 -0
  40. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +2 -3
  41. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +6 -7
  42. data/lib/mongo_mapper/plugins/associations/proxy.rb +8 -6
  43. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  44. data/lib/mongo_mapper/plugins/callbacks.rb +4 -3
  45. data/lib/mongo_mapper/plugins/clone.rb +10 -4
  46. data/lib/mongo_mapper/plugins/descendants.rb +1 -0
  47. data/lib/mongo_mapper/plugins/dirty.rb +1 -0
  48. data/lib/mongo_mapper/plugins/document.rb +41 -0
  49. data/lib/mongo_mapper/plugins/dynamic_querying.rb +41 -0
  50. data/lib/mongo_mapper/{support/find.rb → plugins/dynamic_querying/dynamic_finder.rb} +3 -36
  51. data/lib/mongo_mapper/plugins/embedded_document.rb +49 -0
  52. data/lib/mongo_mapper/plugins/equality.rb +3 -9
  53. data/lib/mongo_mapper/plugins/identity_map.rb +8 -10
  54. data/lib/mongo_mapper/plugins/indexes.rb +12 -0
  55. data/lib/mongo_mapper/plugins/inspect.rb +1 -0
  56. data/lib/mongo_mapper/plugins/keys.rb +15 -27
  57. data/lib/mongo_mapper/plugins/keys/key.rb +14 -3
  58. data/lib/mongo_mapper/plugins/logger.rb +1 -0
  59. data/lib/mongo_mapper/plugins/modifiers.rb +3 -2
  60. data/lib/mongo_mapper/plugins/pagination.rb +5 -15
  61. data/lib/mongo_mapper/plugins/persistence.rb +12 -11
  62. data/lib/mongo_mapper/plugins/protected.rb +8 -0
  63. data/lib/mongo_mapper/plugins/querying.rb +236 -0
  64. data/lib/mongo_mapper/plugins/querying/decorator.rb +46 -0
  65. data/lib/mongo_mapper/plugins/rails.rb +1 -0
  66. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  67. data/lib/mongo_mapper/plugins/sci.rb +32 -0
  68. data/lib/mongo_mapper/plugins/scopes.rb +21 -0
  69. data/lib/mongo_mapper/plugins/serialization.rb +1 -0
  70. data/lib/mongo_mapper/plugins/timestamps.rb +1 -0
  71. data/lib/mongo_mapper/plugins/userstamps.rb +1 -0
  72. data/lib/mongo_mapper/plugins/validations.rb +5 -1
  73. data/lib/mongo_mapper/support/descendant_appends.rb +5 -6
  74. data/lib/mongo_mapper/version.rb +2 -1
  75. data/test/NOTE_ON_TESTING +1 -0
  76. data/test/active_model_lint_test.rb +13 -0
  77. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  78. data/test/functional/associations/test_belongs_to_proxy.rb +93 -0
  79. data/test/functional/associations/test_in_array_proxy.rb +319 -0
  80. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  81. data/test/functional/associations/test_many_documents_proxy.rb +536 -0
  82. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  83. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  84. data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
  85. data/test/functional/associations/test_one_embedded_proxy.rb +58 -0
  86. data/test/functional/associations/test_one_proxy.rb +182 -0
  87. data/test/functional/test_accessible.rb +168 -0
  88. data/test/functional/test_associations.rb +44 -0
  89. data/test/functional/test_binary.rb +27 -0
  90. data/test/functional/test_caching.rb +76 -0
  91. data/test/functional/test_callbacks.rb +151 -0
  92. data/test/functional/test_dirty.rb +163 -0
  93. data/test/functional/test_document.rb +253 -0
  94. data/test/functional/test_dynamic_querying.rb +75 -0
  95. data/test/functional/test_embedded_document.rb +210 -0
  96. data/test/functional/test_identity_map.rb +506 -0
  97. data/test/functional/test_indexes.rb +42 -0
  98. data/test/functional/test_logger.rb +20 -0
  99. data/test/functional/test_modifiers.rb +416 -0
  100. data/test/functional/test_pagination.rb +91 -0
  101. data/test/functional/test_protected.rb +175 -0
  102. data/test/functional/test_querying.rb +873 -0
  103. data/test/functional/test_safe.rb +76 -0
  104. data/test/functional/test_sci.rb +230 -0
  105. data/test/functional/test_scopes.rb +171 -0
  106. data/test/functional/test_string_id_compatibility.rb +67 -0
  107. data/test/functional/test_timestamps.rb +62 -0
  108. data/test/functional/test_userstamps.rb +27 -0
  109. data/test/functional/test_validations.rb +342 -0
  110. data/test/models.rb +227 -0
  111. data/test/test_helper.rb +98 -0
  112. data/test/unit/associations/test_base.rb +212 -0
  113. data/test/unit/associations/test_proxy.rb +105 -0
  114. data/test/unit/serializers/test_json_serializer.rb +202 -0
  115. data/test/unit/test_clone.rb +69 -0
  116. data/test/unit/test_descendant_appends.rb +71 -0
  117. data/test/unit/test_document.rb +213 -0
  118. data/test/unit/test_dynamic_finder.rb +125 -0
  119. data/test/unit/test_embedded_document.rb +644 -0
  120. data/test/unit/test_extensions.rb +380 -0
  121. data/test/unit/test_key.rb +185 -0
  122. data/test/unit/test_keys.rb +55 -0
  123. data/test/unit/test_mongo_mapper.rb +110 -0
  124. data/test/unit/test_pagination.rb +11 -0
  125. data/test/unit/test_plugins.rb +50 -0
  126. data/test/unit/test_rails.rb +181 -0
  127. data/test/unit/test_rails_compatibility.rb +52 -0
  128. data/test/unit/test_serialization.rb +51 -0
  129. data/test/unit/test_time_zones.rb +39 -0
  130. data/test/unit/test_validations.rb +544 -0
  131. metadata +113 -44
  132. data/lib/mongo_mapper/plugins/pagination/proxy.rb +0 -72
  133. data/lib/mongo_mapper/query.rb +0 -23
  134. data/lib/mongo_mapper/support.rb +0 -196
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Scopes
5
+ module ClassMethods
6
+ def scope(name, scope_options={})
7
+ scopes[name] = lambda do |*args|
8
+ result = scope_options.is_a?(Proc) ? scope_options.call(*args) : scope_options
9
+ result = self.query(result) if result.is_a?(Hash)
10
+ self.query.merge(result)
11
+ end
12
+ singleton_class.send :define_method, name, &scopes[name]
13
+ end
14
+
15
+ def scopes
16
+ read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  require 'active_support/json'
2
3
 
3
4
  module MongoMapper
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Timestamps
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Userstamps
@@ -1,8 +1,12 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Plugins
3
4
  module Validations
4
5
  def self.configure(model)
5
- model.class_eval { include Validatable }
6
+ model.class_eval do
7
+ include Validatable
8
+ extend Plugins::Validations::DocumentMacros
9
+ end
6
10
  end
7
11
 
8
12
  module DocumentMacros
@@ -1,3 +1,6 @@
1
+ # encoding: UTF-8
2
+ require 'set'
3
+
1
4
  module MongoMapper
2
5
  module Support
3
6
  module DescendantAppends
@@ -14,9 +17,7 @@ module MongoMapper
14
17
 
15
18
  # @api public
16
19
  def append_extensions(*extensions)
17
- extra_extensions.concat extensions
18
-
19
- # Add the extension to existing descendants
20
+ extra_extensions.concat(extensions)
20
21
  descendants.each do |model|
21
22
  extensions.each { |extension| model.extend(extension) }
22
23
  end
@@ -24,9 +25,7 @@ module MongoMapper
24
25
 
25
26
  # @api public
26
27
  def append_inclusions(*inclusions)
27
- extra_inclusions.concat inclusions
28
-
29
- # Add the inclusion to existing descendants
28
+ extra_inclusions.concat(inclusions)
30
29
  descendants.each do |model|
31
30
  inclusions.each { |inclusion| model.send(:include, inclusion) }
32
31
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
- Version = '0.7.6'
3
+ Version = '0.8.0'
3
4
  end
@@ -0,0 +1 @@
1
+ I am doing my best to keep unit and functional tests separate. As I see them, functional tests hit the database and should never care about internals. Unit tests do not hit the database.
@@ -0,0 +1,13 @@
1
+ require 'test_helper'
2
+ # For testing against edge rails also.
3
+ # $:.unshift '/Users/jnunemaker/dev/ruby/rails/activemodel/lib'
4
+ require 'active_model'
5
+ require 'models'
6
+
7
+ class ActiveModelLintTest < ActiveModel::TestCase
8
+ include ActiveModel::Lint::Tests
9
+
10
+ def setup
11
+ @model = Post.new
12
+ end
13
+ end
@@ -0,0 +1,63 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Status.collection.remove
7
+ Project.collection.remove
8
+ end
9
+
10
+ should "default to nil" do
11
+ status = Status.new
12
+ status.target.nil?.should be_true
13
+ status.target.inspect.should == "nil"
14
+ end
15
+
16
+ should "have boolean presence method" do
17
+ status = Status.new
18
+ status.target?.should be_false
19
+
20
+ status.target = Project.new(:name => 'mongomapper')
21
+ status.target?.should be_true
22
+ end
23
+
24
+ should "be able to replace the association" do
25
+ status = Status.new(:name => 'Foo!')
26
+ project = Project.new(:name => "mongomapper")
27
+ status.target = project
28
+ status.save.should be_true
29
+
30
+ status = status.reload
31
+ status.target.nil?.should be_false
32
+ status.target_id.should == project._id
33
+ status.target_type.should == "Project"
34
+ status.target.name.should == "mongomapper"
35
+ end
36
+
37
+ should "unset the association" do
38
+ status = Status.new(:name => 'Foo!')
39
+ project = Project.new(:name => "mongomapper")
40
+ status.target = project
41
+ status.save.should be_true
42
+
43
+ status = status.reload
44
+ status.target = nil
45
+ status.target_type.nil?.should be_true
46
+ status.target_id.nil?.should be_true
47
+ status.target.nil?.should be_true
48
+ end
49
+
50
+ context "association id set but document not found" do
51
+ setup do
52
+ @status = Status.new(:name => 'Foo!')
53
+ project = Project.new(:name => "mongomapper")
54
+ @status.target = project
55
+ @status.save.should be_true
56
+ project.destroy
57
+ end
58
+
59
+ should "return nil instead of raising error" do
60
+ @status.target.nil?.should be_true
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,93 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class BelongsToProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ @post_class = Doc()
7
+ @comment_class = Doc do
8
+ key :post_id, String
9
+ end
10
+
11
+ @comment_class.belongs_to :post, :class => @post_class
12
+ end
13
+
14
+ should "default to nil" do
15
+ @comment_class.new.post.nil?.should be_true
16
+ end
17
+
18
+ should "have boolean presence method" do
19
+ comment = @comment_class.new(:name => 'Foo!')
20
+ comment.post?.should be_false
21
+
22
+ comment.post = @post_class.new(:name => 'mongomapper')
23
+ comment.post?.should be_true
24
+ end
25
+
26
+ should "be able to replace the association" do
27
+ post = @post_class.new(:name => 'mongomapper')
28
+ comment = @comment_class.new(:name => 'Foo!', :post => post)
29
+ comment.save.should be_true
30
+
31
+ comment = comment.reload
32
+ comment.post.should == post
33
+ comment.post.nil?.should be_false
34
+ end
35
+
36
+ should "unset the association" do
37
+ post = @post_class.new(:name => 'mongomapper')
38
+ comment = @comment_class.new(:name => 'Foo!', :post => post)
39
+ comment.save.should be_true
40
+
41
+ comment = comment.reload
42
+ comment.post = nil
43
+ comment.post.nil?.should be_true
44
+ end
45
+
46
+ should "return nil if id set but document not found" do
47
+ id = BSON::ObjectID.new
48
+ @comment_class.new(:name => 'Foo', :post_id => id).post.nil?.should be_true
49
+ end
50
+
51
+ context ":dependent" do
52
+ setup do
53
+ # FIXME: make use of already defined models
54
+ class ::Property
55
+ include MongoMapper::Document
56
+ end
57
+ Property.collection.remove
58
+
59
+ class ::Thing
60
+ include MongoMapper::Document
61
+ key :name, String
62
+ end
63
+ Thing.collection.remove
64
+ end
65
+
66
+ teardown do
67
+ Object.send :remove_const, 'Property' if defined?(::Property)
68
+ Object.send :remove_const, 'Thing' if defined?(::Thing)
69
+ end
70
+
71
+ context "=> destroy" do
72
+ setup do
73
+ Property.key :thing_id, ObjectId
74
+ Property.belongs_to :thing, :dependent => :destroy
75
+ Thing.many :properties
76
+
77
+ @thing = Thing.create(:name => "Tree")
78
+ @property1 = Property.create
79
+ @property2 = Property.create
80
+ @property3 = Property.create
81
+ @thing.properties << @property1
82
+ @thing.properties << @property2
83
+ @thing.properties << @property3
84
+ end
85
+
86
+ should "not execute on a belongs_to association" do
87
+ Thing.count.should == 1
88
+ @property1.destroy
89
+ Thing.count.should == 1
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,319 @@
1
+ require 'test_helper'
2
+
3
+ class InArrayProxyTest < Test::Unit::TestCase
4
+ context "description" do
5
+ setup do
6
+ class ::List
7
+ include MongoMapper::Document
8
+ key :name, String, :required => true
9
+ end
10
+
11
+ class ::User
12
+ include MongoMapper::Document
13
+ key :name, String, :required => true
14
+ key :list_ids, Array
15
+ many :lists, :in => :list_ids
16
+ end
17
+ User.collection.remove
18
+ List.collection.remove
19
+ end
20
+
21
+ teardown do
22
+ Object.send :remove_const, 'List' if defined?(::List)
23
+ Object.send :remove_const, 'User' if defined?(::User)
24
+ end
25
+
26
+ should "default reader to empty array" do
27
+ User.new.lists.should == []
28
+ end
29
+
30
+ should "allow adding to association like it was an array" do
31
+ user = User.new(:name => 'John')
32
+ user.lists << List.new(:name => 'Foo1!')
33
+ user.lists.push List.new(:name => 'Foo2!')
34
+ user.lists.concat List.new(:name => 'Foo3!')
35
+ user.lists.size.should == 3
36
+ end
37
+
38
+ should "ignore adding duplicate ids" do
39
+ user = User.create(:name => 'John')
40
+ list = List.create(:name => 'Foo')
41
+ user.lists << list
42
+ user.lists << list
43
+ user.lists << list
44
+
45
+ user.list_ids.should == [list.id]
46
+ user.lists.count.should == 1
47
+ end
48
+
49
+ should "be able to replace the association" do
50
+ user = User.new(:name => 'John')
51
+ list = List.new(:name => 'Foo')
52
+ user.lists = [list]
53
+ user.save.should be_true
54
+
55
+ user.reload
56
+ user.list_ids.should == [list.id]
57
+ user.lists.size.should == 1
58
+ user.lists[0].name.should == 'Foo'
59
+ end
60
+
61
+ context "create" do
62
+ setup do
63
+ @user = User.create(:name => 'John')
64
+ @list = @user.lists.create(:name => 'Foo!')
65
+ end
66
+
67
+ should "add id to key" do
68
+ @user.list_ids.should include(@list.id)
69
+ end
70
+
71
+ should "persist id addition to key in database" do
72
+ @user.reload
73
+ @user.list_ids.should include(@list.id)
74
+ end
75
+
76
+ should "add doc to association" do
77
+ @user.lists.should include(@list)
78
+ end
79
+
80
+ should "save doc" do
81
+ @list.should_not be_new
82
+ end
83
+
84
+ should "reset cache" do
85
+ @user.lists.size.should == 1
86
+ @user.lists.create(:name => 'Moo!')
87
+ @user.lists.size.should == 2
88
+ end
89
+ end
90
+
91
+ context "create!" do
92
+ setup do
93
+ @user = User.create(:name => 'John')
94
+ @list = @user.lists.create!(:name => 'Foo!')
95
+ end
96
+
97
+ should "add id to key" do
98
+ @user.list_ids.should include(@list.id)
99
+ end
100
+
101
+ should "persist id addition to key in database" do
102
+ @user.reload
103
+ @user.list_ids.should include(@list.id)
104
+ end
105
+
106
+ should "add doc to association" do
107
+ @user.lists.should include(@list)
108
+ end
109
+
110
+ should "save doc" do
111
+ @list.should_not be_new
112
+ end
113
+
114
+ should "raise exception if invalid" do
115
+ assert_raises(MongoMapper::DocumentNotValid) do
116
+ @user.lists.create!
117
+ end
118
+ end
119
+
120
+ should "reset cache" do
121
+ @user.lists.size.should == 1
122
+ @user.lists.create!(:name => 'Moo!')
123
+ @user.lists.size.should == 2
124
+ end
125
+ end
126
+
127
+ context "Finding scoped to association" do
128
+ setup do
129
+ @user = User.create(:name => 'John')
130
+ @user2 = User.create(:name => 'Brandon')
131
+ @list1 = @user.lists.create!(:name => 'Foo 1', :position => 1)
132
+ @list2 = @user.lists.create!(:name => 'Foo 2', :position => 2)
133
+ @list3 = @user2.lists.create!(:name => 'Foo 3', :position => 1)
134
+ end
135
+
136
+ context "all" do
137
+ should "work" do
138
+ @user.lists.all(:order => :position.asc).should == [@list1, @list2]
139
+ end
140
+
141
+ should "work with conditions" do
142
+ @user.lists.all(:name => 'Foo 1').should == [@list1]
143
+ end
144
+ end
145
+
146
+ context "first" do
147
+ should "work" do
148
+ @user.lists.first(:order => 'position').should == @list1
149
+ end
150
+
151
+ should "work with conditions" do
152
+ @user.lists.first(:position => 2).should == @list2
153
+ end
154
+ end
155
+
156
+ context "last" do
157
+ should "work" do
158
+ @user.lists.last(:order => 'position').should == @list2
159
+ end
160
+
161
+ should "work with conditions" do
162
+ @user.lists.last(:position => 2, :order => 'position').should == @list2
163
+ end
164
+ end
165
+
166
+ context "with one id" do
167
+ should "work for id in association" do
168
+ @user.lists.find(@list1.id).should == @list1
169
+ end
170
+
171
+ should "work with string ids" do
172
+ @user.lists.find(@list1.id.to_s).should == @list1
173
+ end
174
+
175
+ should "not work for id not in association" do
176
+ @user.lists.find(@list3.id).should be_nil
177
+ end
178
+
179
+ should "raise error when using ! and not found" do
180
+ assert_raises MongoMapper::DocumentNotFound do
181
+ @user.lists.find!(@list3.id)
182
+ end
183
+ end
184
+ end
185
+
186
+ context "with multiple ids" do
187
+ should "work for ids in association" do
188
+ @user.lists.find(@list1.id, @list2.id).should == [@list1, @list2]
189
+ end
190
+
191
+ should "not work for ids not in association" do
192
+ @user.lists.find(@list1.id, @list2.id, @list3.id).should == [@list1, @list2]
193
+ end
194
+ end
195
+
196
+ context "with #paginate" do
197
+ setup do
198
+ @lists = @user.lists.paginate(:per_page => 1, :page => 1, :order => 'position')
199
+ end
200
+
201
+ should "return total pages" do
202
+ @lists.total_pages.should == 2
203
+ end
204
+
205
+ should "return total entries" do
206
+ @lists.total_entries.should == 2
207
+ end
208
+
209
+ should "return the subject" do
210
+ @lists.collect(&:name).should == ['Foo 1']
211
+ end
212
+ end
213
+
214
+ context "dynamic finders" do
215
+ should "work with single key" do
216
+ @user.lists.find_by_name('Foo 1').should == @list1
217
+ @user.lists.find_by_name!('Foo 1').should == @list1
218
+ @user.lists.find_by_name('Foo 3').should be_nil
219
+ end
220
+
221
+ should "work with multiple keys" do
222
+ @user.lists.find_by_name_and_position('Foo 1', 1).should == @list1
223
+ @user.lists.find_by_name_and_position!('Foo 1', 1).should == @list1
224
+ @user.lists.find_by_name_and_position('Foo 3', 1).should be_nil
225
+ end
226
+
227
+ should "raise error when using ! and not found" do
228
+ assert_raises(MongoMapper::DocumentNotFound) do
229
+ @user.lists.find_by_name!('Foo 3')
230
+ end
231
+ end
232
+
233
+ context "find_or_create_by" do
234
+ should "not create document if found" do
235
+ lambda {
236
+ list = @user.lists.find_or_create_by_name('Foo 1')
237
+ list.should == @list1
238
+ }.should_not change { List.count }
239
+ end
240
+
241
+ should "create document if not found" do
242
+ lambda {
243
+ list = @user.lists.find_or_create_by_name('Home')
244
+ @user.lists.should include(list)
245
+ }.should change { List.count }
246
+ end
247
+ end
248
+ end
249
+ end
250
+
251
+ context "count" do
252
+ setup do
253
+ @user = User.create(:name => 'John')
254
+ @user2 = User.create(:name => 'Brandon')
255
+ @list1 = @user.lists.create!(:name => 'Foo 1')
256
+ @list2 = @user.lists.create!(:name => 'Foo 2')
257
+ @list3 = @user2.lists.create!(:name => 'Foo 3')
258
+ end
259
+
260
+ should "return number of ids" do
261
+ @user.lists.count.should == 2
262
+ @user2.lists.count.should == 1
263
+ end
264
+
265
+ should "return correct count when given criteria" do
266
+ @user.lists.count(:name => 'Foo 1').should == 1
267
+ @user2.lists.count(:name => 'Foo 1').should == 0
268
+ end
269
+ end
270
+
271
+ context "Removing documents" do
272
+ setup do
273
+ @user = User.create(:name => 'John')
274
+ @user2 = User.create(:name => 'Brandon')
275
+ @list1 = @user.lists.create!(:name => 'Foo 1', :position => 1)
276
+ @list2 = @user.lists.create!(:name => 'Foo 2', :position => 2)
277
+ @list3 = @user2.lists.create!(:name => 'Foo 3', :position => 1)
278
+ end
279
+
280
+ context "destroy_all" do
281
+ should "work" do
282
+ @user.lists.count.should == 2
283
+ @user.lists.destroy_all
284
+ @user.lists.count.should == 0
285
+ end
286
+
287
+ should "work with conditions" do
288
+ @user.lists.count.should == 2
289
+ @user.lists.destroy_all(:name => 'Foo 1')
290
+ @user.lists.count.should == 1
291
+ end
292
+ end
293
+
294
+ context "delete_all" do
295
+ should "work" do
296
+ @user.lists.count.should == 2
297
+ @user.lists.delete_all
298
+ @user.lists.count.should == 0
299
+ end
300
+
301
+ should "work with conditions" do
302
+ @user.lists.count.should == 2
303
+ @user.lists.delete_all(:name => 'Foo 1')
304
+ @user.lists.count.should == 1
305
+ end
306
+ end
307
+
308
+ should "work with nullify" do
309
+ @user.lists.count.should == 2
310
+
311
+ lambda {
312
+ @user.lists.nullify
313
+ }.should_not change { List.count }
314
+
315
+ @user.lists.count.should == 0
316
+ end
317
+ end
318
+ end
319
+ end