mongoid 1.0.6 → 1.1.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 (79) hide show
  1. data/HISTORY +39 -0
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/lib/mongoid.rb +3 -1
  5. data/lib/mongoid/associations.rb +5 -5
  6. data/lib/mongoid/associations/has_many.rb +8 -2
  7. data/lib/mongoid/associations/has_many_related.rb +10 -4
  8. data/lib/mongoid/attributes.rb +19 -13
  9. data/lib/mongoid/commands.rb +12 -6
  10. data/lib/mongoid/commands/create.rb +2 -2
  11. data/lib/mongoid/commands/delete_all.rb +1 -1
  12. data/lib/mongoid/commands/save.rb +2 -2
  13. data/lib/mongoid/components.rb +1 -0
  14. data/lib/mongoid/contexts.rb +4 -0
  15. data/lib/mongoid/contexts/enumerable.rb +105 -0
  16. data/lib/mongoid/contexts/mongo.rb +228 -0
  17. data/lib/mongoid/contexts/paging.rb +42 -0
  18. data/lib/mongoid/criteria.rb +42 -191
  19. data/lib/mongoid/document.rb +19 -13
  20. data/lib/mongoid/extensions.rb +1 -0
  21. data/lib/mongoid/extensions/array/accessors.rb +3 -1
  22. data/lib/mongoid/extensions/float/conversions.rb +1 -1
  23. data/lib/mongoid/extensions/hash/accessors.rb +1 -1
  24. data/lib/mongoid/extensions/integer/conversions.rb +1 -0
  25. data/lib/mongoid/fields.rb +6 -5
  26. data/lib/mongoid/matchers.rb +36 -0
  27. data/lib/mongoid/matchers/all.rb +11 -0
  28. data/lib/mongoid/matchers/default.rb +20 -0
  29. data/lib/mongoid/matchers/exists.rb +13 -0
  30. data/lib/mongoid/matchers/gt.rb +11 -0
  31. data/lib/mongoid/matchers/gte.rb +11 -0
  32. data/lib/mongoid/matchers/in.rb +11 -0
  33. data/lib/mongoid/matchers/lt.rb +11 -0
  34. data/lib/mongoid/matchers/lte.rb +11 -0
  35. data/lib/mongoid/matchers/ne.rb +11 -0
  36. data/lib/mongoid/matchers/nin.rb +11 -0
  37. data/lib/mongoid/matchers/size.rb +11 -0
  38. data/lib/mongoid/scope.rb +17 -1
  39. data/mongoid.gemspec +51 -5
  40. data/spec/integration/mongoid/associations_spec.rb +67 -5
  41. data/spec/integration/mongoid/attributes_spec.rb +22 -0
  42. data/spec/integration/mongoid/commands_spec.rb +51 -12
  43. data/spec/integration/mongoid/criteria_spec.rb +3 -3
  44. data/spec/integration/mongoid/document_spec.rb +8 -8
  45. data/spec/integration/mongoid/finders_spec.rb +1 -1
  46. data/spec/integration/mongoid/inheritance_spec.rb +6 -0
  47. data/spec/integration/mongoid/named_scope_spec.rb +1 -1
  48. data/spec/spec_helper.rb +47 -6
  49. data/spec/unit/mongoid/associations/has_many_related_spec.rb +42 -0
  50. data/spec/unit/mongoid/associations/has_many_spec.rb +40 -1
  51. data/spec/unit/mongoid/attributes_spec.rb +1 -1
  52. data/spec/unit/mongoid/commands/create_spec.rb +3 -3
  53. data/spec/unit/mongoid/commands/delete_all_spec.rb +2 -2
  54. data/spec/unit/mongoid/commands/save_spec.rb +2 -2
  55. data/spec/unit/mongoid/commands_spec.rb +12 -12
  56. data/spec/unit/mongoid/contexts/enumerable_spec.rb +208 -0
  57. data/spec/unit/mongoid/contexts/mongo_spec.rb +370 -0
  58. data/spec/unit/mongoid/criteria_spec.rb +182 -21
  59. data/spec/unit/mongoid/extensions/array/accessors_spec.rb +9 -9
  60. data/spec/unit/mongoid/extensions/date/conversions_spec.rb +2 -1
  61. data/spec/unit/mongoid/extensions/float/conversions_spec.rb +4 -4
  62. data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +1 -1
  63. data/spec/unit/mongoid/fields_spec.rb +3 -3
  64. data/spec/unit/mongoid/identity_spec.rb +2 -2
  65. data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
  66. data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
  67. data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
  68. data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
  69. data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
  70. data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
  71. data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
  72. data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
  73. data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
  74. data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
  75. data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
  76. data/spec/unit/mongoid/matchers_spec.rb +329 -0
  77. data/spec/unit/mongoid/scope_spec.rb +70 -0
  78. data/spec/unit/mongoid/timestamps_spec.rb +2 -2
  79. metadata +50 -4
@@ -3,9 +3,39 @@ require "spec_helper"
3
3
  describe Mongoid::Associations do
4
4
 
5
5
  before do
6
- Mongoid.database.collection(:people).drop
7
- Mongoid.database.collection(:games).drop
8
- Mongoid.database.collection(:posts).drop
6
+ Person.delete_all
7
+ Game.delete_all
8
+ Post.delete_all
9
+ end
10
+
11
+ context "criteria on has many embedded associations" do
12
+
13
+ before do
14
+ @person = Person.new(:title => "Sir")
15
+ @sf_apartment = Address.new(:street => "Genoa Pl", :state => "CA", :address_type => "Apartment")
16
+ @la_home = Address.new(:street => "Rodeo Dr", :state => "CA", :address_type => "Home")
17
+ @sf_home = Address.new(:street => "Pacific", :state => "CA", :address_type => "Home")
18
+ @person.addresses << [ @sf_apartment, @la_home, @sf_home ]
19
+ end
20
+
21
+ it "handles a single criteria" do
22
+ cas = @person.addresses.california
23
+ cas.size.should == 3
24
+ cas.should == [ @sf_apartment, @la_home, @sf_home ]
25
+ end
26
+
27
+ it "handles chained criteria" do
28
+ ca_homes = @person.addresses.california.homes
29
+ ca_homes.size.should == 2
30
+ ca_homes.should == [ @la_home, @sf_home ]
31
+ end
32
+
33
+ it "handles chained criteria with named scopes" do
34
+ ca_homes = @person.addresses.california.homes.rodeo
35
+ ca_homes.size.should == 1
36
+ ca_homes.should == [ @la_home ]
37
+ end
38
+
9
39
  end
10
40
 
11
41
  context "one-to-one relational associations" do
@@ -43,8 +73,8 @@ describe Mongoid::Associations do
43
73
  end
44
74
 
45
75
  it "sets the association on save" do
46
- @from_db = Person.find(@person.id)
47
- @from_db.posts.should == [@post]
76
+ from_db = Person.find(@person.id)
77
+ from_db.posts.should == [@post]
48
78
  end
49
79
 
50
80
  context "when building" do
@@ -60,6 +90,20 @@ describe Mongoid::Associations do
60
90
 
61
91
  end
62
92
 
93
+ context "finding associated objects" do
94
+
95
+ before do
96
+ @extra_post = Post.create(:title => "Orphan")
97
+ end
98
+
99
+ it "returns only those objects scoped to the parent" do
100
+ from_db = Person.find(@person.id)
101
+ Post.all.size.should == 2
102
+ from_db.posts.all.size.should == 1
103
+ end
104
+
105
+ end
106
+
63
107
  end
64
108
 
65
109
  context "nested embedded associations" do
@@ -99,6 +143,24 @@ describe Mongoid::Associations do
99
143
 
100
144
  end
101
145
 
146
+ context "when a has-one to has-many" do
147
+
148
+ before do
149
+ @person = Person.new(:title => "Sir", :ssn => "1")
150
+ @name = Name.new(:first_name => "Syd")
151
+ @person.name = @name
152
+ @person.save
153
+ end
154
+
155
+ it "persists all the associations properly" do
156
+ from_db = Person.find(@person.id)
157
+ translation = Translation.new(:language => "fr")
158
+ from_db.name.translations << translation
159
+ from_db.attributes[:name][:translations].should_not be_nil
160
+ end
161
+
162
+ end
163
+
102
164
  context "when a has-many to has-many" do
103
165
 
104
166
  before do
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Attributes do
4
+
5
+ context "when persisting nil attributes" do
6
+
7
+ before do
8
+ @person = Person.create(:score => nil, :ssn => "555-66-7777")
9
+ end
10
+
11
+ after do
12
+ Person.delete_all
13
+ end
14
+
15
+ it "the field should not exist" do
16
+ from_db = Person.find(@person.id)
17
+ from_db.attributes.has_key?(:score).should be_false
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -10,6 +10,37 @@ describe Mongoid::Commands do
10
10
  @person.delete
11
11
  end
12
12
 
13
+ describe ".create" do
14
+
15
+ it "saves and returns the document" do
16
+ person = Person.create(:title => "Sensei")
17
+ person.should be_a_kind_of(Person)
18
+ person.should_not be_a_new_record
19
+ end
20
+
21
+ end
22
+
23
+ describe ".create!" do
24
+
25
+ context "inserting with a field that is not unique" do
26
+
27
+ context "when a unique index exists" do
28
+
29
+ after do
30
+ Person.delete_all
31
+ end
32
+
33
+ it "raises an error" do
34
+ Person.create!(:ssn => "555-55-9999")
35
+ lambda { Person.create!(:ssn => "555-55-9999") }.should raise_error
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
13
44
  describe "#delete" do
14
45
 
15
46
  before do
@@ -56,16 +87,34 @@ describe Mongoid::Commands do
56
87
 
57
88
  end
58
89
 
90
+ describe "save!" do
91
+
92
+ context "inserting with a field that is not unique" do
93
+
94
+ context "when a unique index exists" do
95
+
96
+ it "raises an error" do
97
+ Person.create!(:ssn => "555-55-9999")
98
+ person = Person.new(:ssn => "555-55-9999")
99
+ lambda { person.save!(:ssn => "555-55-9999") }.should raise_error
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+
106
+ end
107
+
59
108
  describe "#update_attributes" do
60
109
 
61
110
  context "when validation passes" do
62
111
 
63
112
  it "returns true" do
64
- @person.update_attributes(:title => "Blah").should be_true
113
+ @person.update_attributes(:ssn => "555-55-1234").should be_true
65
114
  end
66
115
 
67
116
  it "saves the attributes" do
68
- @person.update_attributes(:title => "Blah")
117
+ @person.update_attributes(:ssn => "555-55-1235", :title => "Blah")
69
118
  @from_db = Person.find(@person.id)
70
119
  @from_db.title.should == "Blah"
71
120
  end
@@ -74,16 +123,6 @@ describe Mongoid::Commands do
74
123
 
75
124
  end
76
125
 
77
- describe ".create" do
78
-
79
- it "saves and returns the document" do
80
- person = Person.create(:title => "Sensei")
81
- person.should be_a_kind_of(Person)
82
- person.should_not be_a_new_record
83
- end
84
-
85
- end
86
-
87
126
  describe ".delete_all" do
88
127
 
89
128
  it "returns true" do
@@ -6,7 +6,7 @@ describe Mongoid::Criteria do
6
6
 
7
7
  before do
8
8
  10.times do |n|
9
- Person.create(:title => "Sir", :age => (n * 10), :aliases => ["D", "Durran"])
9
+ Person.create(:title => "Sir", :age => (n * 10), :aliases => ["D", "Durran"], :ssn => "#{n}")
10
10
  end
11
11
  end
12
12
 
@@ -24,7 +24,7 @@ describe Mongoid::Criteria do
24
24
 
25
25
  before do
26
26
  10.times do |n|
27
- Person.create(:title => "Sir", :age => ((n + 1) * 10), :aliases => ["D", "Durran"])
27
+ Person.create(:title => "Sir", :age => ((n + 1) * 10), :aliases => ["D", "Durran"], :ssn => "#{n}")
28
28
  end
29
29
  end
30
30
 
@@ -42,7 +42,7 @@ describe Mongoid::Criteria do
42
42
 
43
43
  before do
44
44
  10.times do |n|
45
- Person.create(:title => "Sir", :age => 5, :aliases => ["D", "Durran"])
45
+ Person.create(:title => "Sir", :age => 5, :aliases => ["D", "Durran"], :ssn => "#{n}")
46
46
  end
47
47
  end
48
48
 
@@ -3,7 +3,7 @@ require "spec_helper"
3
3
  describe Mongoid::Document do
4
4
 
5
5
  before do
6
- Mongoid.database.collection(:people).drop
6
+ Person.delete_all
7
7
  end
8
8
 
9
9
  context "when document contains a hash field" do
@@ -50,7 +50,7 @@ describe Mongoid::Document do
50
50
 
51
51
  before do
52
52
  5.times do |n|
53
- Person.create(:title => "Sir")
53
+ Person.create(:title => "Sir", :ssn => "#{n}")
54
54
  end
55
55
  end
56
56
 
@@ -87,10 +87,10 @@ describe Mongoid::Document do
87
87
  context "chaining criteria scopes" do
88
88
 
89
89
  before do
90
- @one = Person.create(:title => "Mr", :age => 55, :terms => true)
91
- @two = Person.create(:title => "Sir", :age => 55, :terms => true)
92
- @three = Person.create(:title => "Sir", :age => 35, :terms => true)
93
- @four = Person.create(:title => "Sir", :age => 55, :terms => false)
90
+ @one = Person.create(:title => "Mr", :age => 55, :terms => true, :ssn => "q")
91
+ @two = Person.create(:title => "Sir", :age => 55, :terms => true, :ssn => "w")
92
+ @three = Person.create(:title => "Sir", :age => 35, :terms => true, :ssn => "e")
93
+ @four = Person.create(:title => "Sir", :age => 55, :terms => false, :ssn => "r")
94
94
  end
95
95
 
96
96
  it "finds by the merged criteria" do
@@ -120,7 +120,7 @@ describe Mongoid::Document do
120
120
 
121
121
  before do
122
122
  @person = Person.create(:title => "Lead")
123
- @person.addresses.create(:street => "1st Street")
123
+ address = @person.addresses.create(:street => "1st Street")
124
124
  @person.create_name(:first_name => "Emmanuel")
125
125
  @person.save
126
126
  end
@@ -288,7 +288,7 @@ describe Mongoid::Document do
288
288
 
289
289
  before do
290
290
  10.times do |num|
291
- Person.create(:title => "Test-#{num}")
291
+ Person.create(:title => "Test-#{num}", :ssn => "55#{num}")
292
292
  end
293
293
  end
294
294
 
@@ -5,7 +5,7 @@ describe Mongoid::Finders do
5
5
  describe "#find" do
6
6
 
7
7
  before do
8
- @document = Person.create(:title => "Mrs.")
8
+ @document = Person.create(:title => "Mrs.", :ssn => "another")
9
9
  end
10
10
 
11
11
  after do
@@ -2,6 +2,12 @@ require "spec_helper"
2
2
 
3
3
  describe Mongoid::Document do
4
4
 
5
+ before do
6
+ Browser.delete_all
7
+ Firefox.delete_all
8
+ Canvas.delete_all
9
+ end
10
+
5
11
  context "when document is a subclass of a root class" do
6
12
 
7
13
  before do
@@ -4,7 +4,7 @@ describe Mongoid::NamedScope do
4
4
 
5
5
  describe ".named_scope" do
6
6
 
7
- class Person
7
+ class ::Person
8
8
  named_scope :doctors, {:where => {:title => 'Dr.'} }
9
9
  named_scope :old, criteria.where(:age.gt => 50)
10
10
  end
@@ -38,6 +38,14 @@ class Person
38
38
  field :map, :type => Hash
39
39
  field :score, :type => Integer
40
40
  field :blood_alcohol_content, :type => Float
41
+ field :ssn
42
+
43
+ index :age
44
+ index :addresses
45
+ index :dob
46
+ index :name
47
+ index :title
48
+ index :ssn, :unique => true
41
49
 
42
50
  attr_reader :rescored
43
51
 
@@ -50,12 +58,6 @@ class Person
50
58
  accepts_nested_attributes_for :addresses, :reject_if => lambda { |attrs| attrs["street"].blank? }
51
59
  accepts_nested_attributes_for :name
52
60
 
53
- index :age
54
- index :addresses
55
- index :dob
56
- index :name
57
- index :title
58
-
59
61
  has_one_related :game
60
62
  has_many_related :posts
61
63
 
@@ -145,18 +147,34 @@ end
145
147
 
146
148
  class Address
147
149
  include Mongoid::Document
150
+ field :address_type
151
+ field :number, :type => Integer
148
152
  field :street
149
153
  field :city
150
154
  field :state
151
155
  field :post_code
152
156
  field :parent_title
157
+ field :services, :type => Array
153
158
  key :street
154
159
  has_many :locations
155
160
  belongs_to :addressable, :inverse_of => :addresses
156
161
 
162
+ named_scope :rodeo, where(:street => "Rodeo Dr")
163
+
157
164
  def set_parent=(set = false)
158
165
  self.parent_title = addressable.title if set
159
166
  end
167
+
168
+ class << self
169
+ def california
170
+ where(:state => "CA")
171
+ end
172
+
173
+ def homes
174
+ where(:address_type => "Home")
175
+ end
176
+
177
+ end
160
178
  end
161
179
 
162
180
  class Location
@@ -171,6 +189,7 @@ class Name
171
189
  field :last_name
172
190
  field :parent_title
173
191
  key :first_name, :last_name
192
+ has_many :translations
174
193
  belongs_to :person, :inverse_of => :name
175
194
 
176
195
  def set_parent=(set = false)
@@ -178,6 +197,12 @@ class Name
178
197
  end
179
198
  end
180
199
 
200
+ class Translation
201
+ include Mongoid::Document
202
+ field :language
203
+ belongs_to :name, :inverse_of => :translations
204
+ end
205
+
181
206
  class Comment
182
207
  include Mongoid::Document
183
208
  include Mongoid::Versioning
@@ -292,3 +317,19 @@ module Medical
292
317
  field :name
293
318
  end
294
319
  end
320
+
321
+ ###################################
322
+
323
+ class Author
324
+ include Mongoid::Document
325
+ field :name
326
+ has_many :books
327
+ end
328
+
329
+ class Book
330
+ include Mongoid::Document
331
+ field :title
332
+ belongs_to :author, :inverse_of => :books
333
+ end
334
+
335
+
@@ -193,6 +193,48 @@ describe Mongoid::Associations::HasManyRelated do
193
193
 
194
194
  end
195
195
 
196
+ context "when finding all with conditions" do
197
+
198
+ before do
199
+ @post = stub
200
+ end
201
+
202
+ it "passes the conditions to the association class" do
203
+ Post.expects(:find).with(:all, :conditions => { :title => "Testing", :person_id => @parent.id }).returns([@post])
204
+ posts = @association.find(:all, :conditions => { :title => "Testing" })
205
+ posts.should == [@post]
206
+ end
207
+
208
+ end
209
+
210
+ context "when finding first with conditions" do
211
+
212
+ before do
213
+ @post = stub
214
+ end
215
+
216
+ it "passes the conditions to the association class" do
217
+ Post.expects(:find).with(:first, :conditions => { :title => "Testing", :person_id => @parent.id }).returns(@post)
218
+ post = @association.find(:first, :conditions => { :title => "Testing" })
219
+ post.should == @post
220
+ end
221
+
222
+ end
223
+
224
+ context "when finding last with conditions" do
225
+
226
+ before do
227
+ @post = stub
228
+ end
229
+
230
+ it "passes the conditions to the association class" do
231
+ Post.expects(:find).with(:last, :conditions => { :title => "Testing", :person_id => @parent.id }).returns(@post)
232
+ post = @association.find(:last, :conditions => { :title => "Testing" })
233
+ post.should == @post
234
+ end
235
+
236
+ end
237
+
196
238
  end
197
239
 
198
240
  describe ".initialize" do