mongo_mapper 0.7.6 → 0.8.0

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