mrkurt-mongo_mapper 0.6.8

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 (77) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +38 -0
  4. data/Rakefile +55 -0
  5. data/VERSION +1 -0
  6. data/bin/mmconsole +60 -0
  7. data/lib/mongo_mapper.rb +139 -0
  8. data/lib/mongo_mapper/associations.rb +72 -0
  9. data/lib/mongo_mapper/associations/base.rb +113 -0
  10. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +26 -0
  11. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +21 -0
  12. data/lib/mongo_mapper/associations/collection.rb +19 -0
  13. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +26 -0
  14. data/lib/mongo_mapper/associations/many_documents_proxy.rb +115 -0
  15. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +31 -0
  16. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +54 -0
  17. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +11 -0
  18. data/lib/mongo_mapper/associations/one_proxy.rb +61 -0
  19. data/lib/mongo_mapper/associations/proxy.rb +111 -0
  20. data/lib/mongo_mapper/callbacks.rb +61 -0
  21. data/lib/mongo_mapper/dirty.rb +117 -0
  22. data/lib/mongo_mapper/document.rb +496 -0
  23. data/lib/mongo_mapper/dynamic_finder.rb +74 -0
  24. data/lib/mongo_mapper/embedded_document.rb +380 -0
  25. data/lib/mongo_mapper/finder_options.rb +145 -0
  26. data/lib/mongo_mapper/key.rb +36 -0
  27. data/lib/mongo_mapper/mongo_mapper.rb +125 -0
  28. data/lib/mongo_mapper/pagination.rb +66 -0
  29. data/lib/mongo_mapper/rails_compatibility/document.rb +15 -0
  30. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +28 -0
  31. data/lib/mongo_mapper/serialization.rb +54 -0
  32. data/lib/mongo_mapper/serializers/json_serializer.rb +48 -0
  33. data/lib/mongo_mapper/support.rb +192 -0
  34. data/lib/mongo_mapper/validations.rb +39 -0
  35. data/mongo_mapper.gemspec +173 -0
  36. data/specs.watchr +30 -0
  37. data/test/NOTE_ON_TESTING +1 -0
  38. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +55 -0
  39. data/test/functional/associations/test_belongs_to_proxy.rb +91 -0
  40. data/test/functional/associations/test_many_documents_as_proxy.rb +246 -0
  41. data/test/functional/associations/test_many_documents_proxy.rb +477 -0
  42. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +156 -0
  43. data/test/functional/associations/test_many_embedded_proxy.rb +192 -0
  44. data/test/functional/associations/test_many_polymorphic_proxy.rb +339 -0
  45. data/test/functional/associations/test_one_proxy.rb +131 -0
  46. data/test/functional/test_associations.rb +44 -0
  47. data/test/functional/test_binary.rb +33 -0
  48. data/test/functional/test_callbacks.rb +85 -0
  49. data/test/functional/test_dirty.rb +159 -0
  50. data/test/functional/test_document.rb +1198 -0
  51. data/test/functional/test_embedded_document.rb +135 -0
  52. data/test/functional/test_logger.rb +20 -0
  53. data/test/functional/test_modifiers.rb +242 -0
  54. data/test/functional/test_pagination.rb +95 -0
  55. data/test/functional/test_rails_compatibility.rb +25 -0
  56. data/test/functional/test_string_id_compatibility.rb +72 -0
  57. data/test/functional/test_validations.rb +361 -0
  58. data/test/models.rb +271 -0
  59. data/test/support/custom_matchers.rb +55 -0
  60. data/test/support/timing.rb +16 -0
  61. data/test/test_helper.rb +27 -0
  62. data/test/unit/associations/test_base.rb +182 -0
  63. data/test/unit/associations/test_proxy.rb +91 -0
  64. data/test/unit/serializers/test_json_serializer.rb +189 -0
  65. data/test/unit/test_document.rb +236 -0
  66. data/test/unit/test_dynamic_finder.rb +125 -0
  67. data/test/unit/test_embedded_document.rb +709 -0
  68. data/test/unit/test_finder_options.rb +325 -0
  69. data/test/unit/test_key.rb +172 -0
  70. data/test/unit/test_mongo_mapper.rb +65 -0
  71. data/test/unit/test_pagination.rb +119 -0
  72. data/test/unit/test_rails_compatibility.rb +52 -0
  73. data/test/unit/test_serializations.rb +52 -0
  74. data/test/unit/test_support.rb +346 -0
  75. data/test/unit/test_time_zones.rb +40 -0
  76. data/test/unit/test_validations.rb +503 -0
  77. metadata +239 -0
@@ -0,0 +1,156 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyEmbeddedPolymorphicProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Catalog.collection.remove
7
+ TrModels::Fleet.collection.remove
8
+ end
9
+
10
+ should "default reader to empty array" do
11
+ catalog = Catalog.new
12
+ catalog.medias.should == []
13
+ end
14
+
15
+ should "allow adding to association like it was an array" do
16
+ catalog = Catalog.new
17
+ catalog.medias << Video.new
18
+ catalog.medias.push Video.new
19
+ catalog.medias.size.should == 2
20
+ end
21
+
22
+ should "be able to replace the association" do
23
+ catalog = Catalog.new
24
+ catalog.medias = [Video.new("file" => "video.mpg", "length" => 3600)]
25
+ catalog.save.should be_true
26
+
27
+ catalog = catalog.reload
28
+ catalog.medias.size.should == 1
29
+ catalog.medias[0].file.should == "video.mpg"
30
+ end
31
+
32
+ should "store different associations" do
33
+ catalog = Catalog.new
34
+ catalog.medias = [
35
+ Video.new("file" => "video.mpg", "length" => 3600),
36
+ Music.new("file" => "music.mp3", "bitrate" => "128kbps"),
37
+ Image.new("file" => "image.png", "width" => 800, "height" => 600)
38
+ ]
39
+ catalog.save.should be_true
40
+
41
+ catalog = catalog.reload
42
+ catalog.medias.size.should == 3
43
+ catalog.medias[0].file.should == "video.mpg"
44
+ catalog.medias[0].length.should == 3600
45
+ catalog.medias[1].file.should == "music.mp3"
46
+ catalog.medias[1].bitrate.should == "128kbps"
47
+ catalog.medias[2].file.should == "image.png"
48
+ catalog.medias[2].width.should == 800
49
+ catalog.medias[2].height.should == 600
50
+ end
51
+
52
+ context "With modularized models" do
53
+ should "set associations correctly" do
54
+ fleet_attributes = {
55
+ "name" => "My Fleet",
56
+ "transports" => [
57
+ {"_type" => "TrModels::Ambulance", "license_plate" => "GGG123", "icu" => true},
58
+ {"_type" => "TrModels::Car", "license_plate" => "ABC123", "model" => "VW Golf", "year" => 2001},
59
+ {"_type" => "TrModels::Car", "license_plate" => "DEF123", "model" => "Honda Accord", "year" => 2008},
60
+ ]
61
+ }
62
+
63
+ fleet = TrModels::Fleet.new(fleet_attributes)
64
+ fleet.transports.size.should == 3
65
+ fleet.transports[0].class.should == TrModels::Ambulance
66
+ fleet.transports[0].license_plate.should == "GGG123"
67
+ fleet.transports[0].icu.should be_true
68
+ fleet.transports[1].class.should == TrModels::Car
69
+ fleet.transports[1].license_plate.should == "ABC123"
70
+ fleet.transports[1].model.should == "VW Golf"
71
+ fleet.transports[1].year.should == 2001
72
+ fleet.transports[2].class.should == TrModels::Car
73
+ fleet.transports[2].license_plate.should == "DEF123"
74
+ fleet.transports[2].model.should == "Honda Accord"
75
+ fleet.transports[2].year.should == 2008
76
+ fleet.save.should be_true
77
+
78
+ fleet = fleet.reload
79
+ fleet.transports.size.should == 3
80
+ fleet.transports[0].license_plate.should == "GGG123"
81
+ fleet.transports[0].icu.should be_true
82
+ fleet.transports[1].license_plate.should == "ABC123"
83
+ fleet.transports[1].model.should == "VW Golf"
84
+ fleet.transports[1].year.should == 2001
85
+ fleet.transports[2].license_plate.should == "DEF123"
86
+ fleet.transports[2].model.should == "Honda Accord"
87
+ fleet.transports[2].year.should == 2008
88
+ end
89
+
90
+ should "default reader to empty array" do
91
+ fleet = TrModels::Fleet.new
92
+ fleet.transports.should == []
93
+ end
94
+
95
+ should "allow adding to association like it was an array" do
96
+ fleet = TrModels::Fleet.new
97
+ fleet.transports << TrModels::Car.new
98
+ fleet.transports.push TrModels::Bus.new
99
+ fleet.transports.size.should == 2
100
+ end
101
+
102
+ should "be able to replace the association" do
103
+ fleet = TrModels::Fleet.new
104
+ fleet.transports = [TrModels::Car.new("license_plate" => "DCU2013", "model" => "Honda Civic")]
105
+ fleet.save.should be_true
106
+
107
+ fleet = fleet.reload
108
+ fleet.transports.size.should == 1
109
+ fleet.transports[0].license_plate.should == "DCU2013"
110
+ end
111
+
112
+ should "store different associations" do
113
+ fleet = TrModels::Fleet.new
114
+ fleet.transports = [
115
+ TrModels::Car.new("license_plate" => "ABC1223", "model" => "Honda Civic", "year" => 2003),
116
+ TrModels::Bus.new("license_plate" => "XYZ9090", "max_passengers" => 51),
117
+ TrModels::Ambulance.new("license_plate" => "HDD3030", "icu" => true)
118
+ ]
119
+ fleet.save.should be_true
120
+
121
+ fleet = fleet.reload
122
+ fleet.transports.size.should == 3
123
+ fleet.transports[0].license_plate.should == "ABC1223"
124
+ fleet.transports[0].model.should == "Honda Civic"
125
+ fleet.transports[0].year.should == 2003
126
+ fleet.transports[1].license_plate.should == "XYZ9090"
127
+ fleet.transports[1].max_passengers.should == 51
128
+ fleet.transports[2].license_plate.should == "HDD3030"
129
+ fleet.transports[2].icu.should == true
130
+ end
131
+ end
132
+
133
+ context "extending the association" do
134
+ should "work using a block passed to many" do
135
+ catalog = Catalog.new
136
+ medias = catalog.medias = [
137
+ Video.new("file" => "video.mpg", "length" => 3600, :visible => true),
138
+ Music.new("file" => "music.mp3", "bitrate" => "128kbps", :visible => true),
139
+ Image.new("file" => "image.png", "width" => 800, "height" => 600, :visible => false)
140
+ ]
141
+ catalog.save
142
+ catalog.medias.visible.should == [medias[0], medias[1]]
143
+ end
144
+
145
+ should "work using many's :extend option" do
146
+ fleet = TrModels::Fleet.new
147
+ transports = fleet.transports = [
148
+ TrModels::Car.new("license_plate" => "ABC1223", "model" => "Honda Civic", "year" => 2003, :purchased_on => 2.years.ago.to_date),
149
+ TrModels::Bus.new("license_plate" => "XYZ9090", "max_passengers" => 51, :purchased_on => 3.years.ago.to_date),
150
+ TrModels::Ambulance.new("license_plate" => "HDD3030", "icu" => true, :purchased_on => 1.year.ago.to_date)
151
+ ]
152
+ fleet.save
153
+ fleet.transports.to_be_replaced.should == [transports[1]]
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,192 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyEmbeddedProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Project.collection.remove
7
+ RealPerson.collection.remove
8
+ end
9
+
10
+ should "default reader to empty array" do
11
+ Project.new.addresses.should == []
12
+ end
13
+
14
+ should "allow adding to association like it was an array" do
15
+ project = Project.new
16
+ project.addresses << Address.new
17
+ project.addresses.push Address.new
18
+ project.addresses.size.should == 2
19
+ end
20
+
21
+ should "be embedded in document on save" do
22
+ sb = Address.new(:city => 'South Bend', :state => 'IN')
23
+ chi = Address.new(:city => 'Chicago', :state => 'IL')
24
+ project = Project.new
25
+ project.addresses << sb
26
+ project.addresses << chi
27
+ project.save
28
+
29
+ project.reload
30
+ project.addresses.size.should == 2
31
+ project.addresses[0].should == sb
32
+ project.addresses[1].should == chi
33
+ end
34
+
35
+ should "allow embedding arbitrarily deep" do
36
+ @document = Class.new do
37
+ include MongoMapper::Document
38
+ set_collection_name 'test'
39
+ key :person, Person
40
+ end
41
+ @document.collection.remove
42
+
43
+ meg = Person.new(:name => "Meg")
44
+ meg.child = Person.new(:name => "Steve")
45
+ meg.child.child = Person.new(:name => "Linda")
46
+
47
+ doc = @document.new(:person => meg)
48
+ doc.save
49
+
50
+ doc.reload
51
+ doc.person.name.should == 'Meg'
52
+ doc.person.child.name.should == 'Steve'
53
+ doc.person.child.child.name.should == 'Linda'
54
+ end
55
+
56
+ should "allow assignment of 'many' embedded documents using a hash" do
57
+ person_attributes = {
58
+ "name" => "Mr. Pet Lover",
59
+ "pets" => [
60
+ {"name" => "Jimmy", "species" => "Cocker Spainel"},
61
+ {"name" => "Sasha", "species" => "Siberian Husky"},
62
+ ]
63
+ }
64
+
65
+ pet_lover = RealPerson.new(person_attributes)
66
+ pet_lover.name.should == "Mr. Pet Lover"
67
+ pet_lover.pets[0].name.should == "Jimmy"
68
+ pet_lover.pets[0].species.should == "Cocker Spainel"
69
+ pet_lover.pets[1].name.should == "Sasha"
70
+ pet_lover.pets[1].species.should == "Siberian Husky"
71
+ pet_lover.save.should be_true
72
+
73
+ pet_lover.reload
74
+ pet_lover.name.should == "Mr. Pet Lover"
75
+ pet_lover.pets[0].name.should == "Jimmy"
76
+ pet_lover.pets[0].species.should == "Cocker Spainel"
77
+ pet_lover.pets[1].name.should == "Sasha"
78
+ pet_lover.pets[1].species.should == "Siberian Husky"
79
+ end
80
+
81
+ context "embedding many embedded documents" do
82
+ setup do
83
+ @document = Class.new do
84
+ include MongoMapper::Document
85
+ set_collection_name 'test'
86
+ many :people
87
+ end
88
+ @document.collection.remove
89
+ end
90
+
91
+ should "persist all embedded documents" do
92
+ meg = Person.new(:name => "Meg")
93
+ sparky = Pet.new(:name => "Sparky", :species => "Dog")
94
+ koda = Pet.new(:name => "Koda", :species => "Dog")
95
+
96
+ doc = @document.new
97
+ meg.pets << sparky
98
+ meg.pets << koda
99
+ doc.people << meg
100
+ doc.save
101
+
102
+ doc.reload
103
+ doc.people.first.name.should == "Meg"
104
+ doc.people.first.pets.should_not == []
105
+ doc.people.first.pets.first.name.should == "Sparky"
106
+ doc.people.first.pets.first.species.should == "Dog"
107
+ doc.people.first.pets[1].name.should == "Koda"
108
+ doc.people.first.pets[1].species.should == "Dog"
109
+ end
110
+
111
+ should "create a reference to the root document for all embedded documents before save" do
112
+ meg = Person.new(:name => "Meg")
113
+ sparky = Pet.new(:name => "Sparky", :species => "Dog")
114
+ doc = @document.new
115
+ doc.people << meg
116
+ meg.pets << sparky
117
+
118
+ doc.people.first._root_document.should == doc
119
+ doc.people.first.pets.first._root_document.should == doc
120
+ end
121
+
122
+ should "create a reference to the root document for all embedded documents" do
123
+ sparky = Pet.new(:name => "Sparky", :species => "Dog")
124
+ meg = Person.new(:name => "Meg", :pets => [sparky])
125
+ doc = @document.new
126
+ doc.people << meg
127
+ doc.save
128
+
129
+ doc.reload
130
+ doc.people.first._root_document.should == doc
131
+ doc.people.first.pets.first._root_document.should == doc
132
+ end
133
+ end
134
+
135
+ should "allow finding by id" do
136
+ sparky = Pet.new(:name => "Sparky", :species => "Dog")
137
+ meg = Person.new(:name => "Meg", :pets => [sparky])
138
+
139
+ meg.pets.find(sparky._id).should == sparky # oid
140
+ meg.pets.find(sparky.id.to_s).should == sparky # string
141
+ end
142
+
143
+ context "extending the association" do
144
+ setup do
145
+ @address_class = Class.new do
146
+ include MongoMapper::EmbeddedDocument
147
+ key :address, String
148
+ key :city, String
149
+ key :state, String
150
+ key :zip, Integer
151
+ end
152
+
153
+ @project_class = Class.new do
154
+ include MongoMapper::Document
155
+ key :name, String
156
+ end
157
+
158
+ @project_class.collection.remove
159
+ end
160
+
161
+ should "work using a block passed to many" do
162
+ @project_class.many :addresses, :class => @address_class do
163
+ def find_all_by_state(state)
164
+ find_all { |a| a.state == state }
165
+ end
166
+ end
167
+
168
+ addr1 = @address_class.new(:address => "Gate-3 Lankershim Blvd.", :city => "Universal City", :state => "CA", :zip => "91608")
169
+ addr2 = @address_class.new(:address => "3000 W. Alameda Ave.", :city => "Burbank", :state => "CA", :zip => "91523")
170
+ addr3 = @address_class.new(:address => "111 Some Ln", :city => "Nashville", :state => "TN", :zip => "37211")
171
+ project = @project_class.create(:name => "Some Project", :addresses => [addr1, addr2, addr3])
172
+
173
+ project.addresses.find_all_by_state("CA").should == [addr1, addr2]
174
+ end
175
+
176
+ should "work using many's :extend option" do
177
+ module FindByCity
178
+ def find_by_city(city)
179
+ find_all { |a| a.city == city }
180
+ end
181
+ end
182
+ @project_class.many :addresses, :class => @address_class, :extend => FindByCity
183
+
184
+ addr1 = @address_class.new(:address => "Gate-3 Lankershim Blvd.", :city => "Universal City", :state => "CA", :zip => "91608")
185
+ addr2 = @address_class.new(:address => "3000 W. Alameda Ave.", :city => "Burbank", :state => "CA", :zip => "91523")
186
+ addr3 = @address_class.new(:address => "111 Some Ln", :city => "Nashville", :state => "TN", :zip => "37211")
187
+ project = @project_class.create(:name => "Some Project", :addresses => [addr1, addr2, addr3])
188
+
189
+ project.addresses.find_by_city('Burbank').should == [addr2]
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,339 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyPolymorphicProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Room.collection.remove
7
+ Message.collection.remove
8
+ end
9
+
10
+ should "default reader to empty array" do
11
+ Room.new.messages.should == []
12
+ end
13
+
14
+ should "add type key to polymorphic class base" do
15
+ Message.keys.keys.should include('_type')
16
+ end
17
+
18
+ should "allow adding to assiciation like it was an array" do
19
+ room = Room.new
20
+ room.messages << Enter.new
21
+ room.messages.push Exit.new
22
+ room.messages.concat Exit.new
23
+ room.messages.size.should == 3
24
+ end
25
+
26
+ should "be able to replace the association" do
27
+ room = Room.create(:name => 'Lounge')
28
+
29
+ lambda {
30
+ room.messages = [
31
+ Enter.new(:body => 'John entered room', :position => 1),
32
+ Chat.new(:body => 'Heyyyoooo!', :position => 2),
33
+ Exit.new(:body => 'John exited room', :position => 3)
34
+ ]
35
+ }.should change { Message.count }.by(3)
36
+
37
+ room = room.reload
38
+ messages = room.messages.all :order => "position"
39
+ messages.size.should == 3
40
+ messages[0].body.should == 'John entered room'
41
+ messages[1].body.should == 'Heyyyoooo!'
42
+ messages[2].body.should == 'John exited room'
43
+ end
44
+
45
+ should "correctly store type when using <<, push and concat" do
46
+ room = Room.new
47
+ room.messages << Enter.new(:body => 'John entered the room', :position => 1)
48
+ room.messages.push Exit.new(:body => 'John entered the room', :position => 2)
49
+ room.messages.concat Chat.new(:body => 'Holla!' , :position => 3)
50
+
51
+ room = room.reload
52
+ messages = room.messages.all :order => "position"
53
+ messages[0]._type.should == 'Enter'
54
+ messages[1]._type.should == 'Exit'
55
+ messages[2]._type.should == 'Chat'
56
+ end
57
+
58
+ context "build" do
59
+ should "assign foreign key" do
60
+ room = Room.create
61
+ message = room.messages.build
62
+ message.room_id.should == room._id
63
+ end
64
+
65
+ should "assign _type" do
66
+ room = Room.create
67
+ message = room.messages.build
68
+ message._type.should == 'Message'
69
+ end
70
+
71
+ should "allow assigning attributes" do
72
+ room = Room.create
73
+ message = room.messages.build(:body => 'Foo!')
74
+ message.body.should == 'Foo!'
75
+ end
76
+ end
77
+
78
+ context "create" do
79
+ should "assign foreign key" do
80
+ room = Room.create
81
+ message = room.messages.create
82
+ message.room_id.should == room._id
83
+ end
84
+
85
+ should "assign _type" do
86
+ room = Room.create
87
+ message = room.messages.create
88
+ message._type.should == 'Message'
89
+ end
90
+
91
+ should "save record" do
92
+ room = Room.create
93
+ lambda {
94
+ room.messages.create
95
+ }.should change { Message.count }
96
+ end
97
+
98
+ should "allow passing attributes" do
99
+ room = Room.create
100
+ message = room.messages.create(:body => 'Foo!')
101
+ message.body.should == 'Foo!'
102
+ end
103
+ end
104
+
105
+ context "count" do
106
+ should "work scoped to association" do
107
+ room = Room.create
108
+ 3.times { room.messages.create }
109
+
110
+ other_room = Room.create
111
+ 2.times { other_room.messages.create }
112
+
113
+ room.messages.count.should == 3
114
+ other_room.messages.count.should == 2
115
+ end
116
+
117
+ should "work with conditions" do
118
+ room = Room.create
119
+ room.messages.create(:body => 'Foo')
120
+ room.messages.create(:body => 'Other 1')
121
+ room.messages.create(:body => 'Other 2')
122
+
123
+ room.messages.count(:body => 'Foo').should == 1
124
+ end
125
+ end
126
+
127
+ context "Finding scoped to association" do
128
+ setup do
129
+ @lounge = Room.create(:name => 'Lounge')
130
+ @lm1 = Message.create(:body => 'Loungin!', :position => 1)
131
+ @lm2 = Message.create(:body => 'I love loungin!', :position => 2)
132
+ @lounge.messages = [@lm1, @lm2]
133
+ @lounge.save
134
+
135
+ @hall = Room.create(:name => 'Hall')
136
+ @hm1 = Message.create(:body => 'Do not fall in the hall', :position => 1)
137
+ @hm3 = Message.create(:body => 'Loungin!', :position => 3)
138
+ @hm2 = Message.create(:body => 'Hall the king!', :position => 2)
139
+ @hall.messages = [@hm1, @hm2, @hm3]
140
+ @hall.save
141
+ end
142
+
143
+ context "dynamic finders" do
144
+ should "work with single key" do
145
+ @lounge.messages.find_by_position(1).should == @lm1
146
+ @hall.messages.find_by_position(2).should == @hm2
147
+ end
148
+
149
+ should "work with multiple keys" do
150
+ @lounge.messages.find_by_body_and_position('Loungin!', 1).should == @lm1
151
+ @lounge.messages.find_by_body_and_position('Loungin!', 2).should be_nil
152
+ end
153
+
154
+ should "raise error when using !" do
155
+ lambda {
156
+ @lounge.messages.find_by_position!(222)
157
+ }.should raise_error(MongoMapper::DocumentNotFound)
158
+ end
159
+
160
+ context "find_or_create_by" do
161
+ should "not create document if found" do
162
+ lambda {
163
+ message = @lounge.messages.find_or_create_by_body('Loungin!')
164
+ message.room.should == @lounge
165
+ message.should == @lm1
166
+ }.should_not change { Message.count }
167
+ end
168
+
169
+ should "create document if not found" do
170
+ lambda {
171
+ message = @lounge.messages.find_or_create_by_body('Yo dawg!')
172
+ message.room.should == @lounge
173
+ message._type.should == 'Message'
174
+ }.should change { Message.count }.by(1)
175
+ end
176
+ end
177
+ end
178
+
179
+ context "with :all" do
180
+ should "work" do
181
+ @lounge.messages.find(:all, :order => "position").should == [@lm1, @lm2]
182
+ end
183
+
184
+ should "work with conditions" do
185
+ messages = @lounge.messages.find(:all, :body => 'Loungin!', :order => "position")
186
+ messages.should == [@lm1]
187
+ end
188
+
189
+ should "work with order" do
190
+ messages = @lounge.messages.find(:all, :order => 'position desc')
191
+ messages.should == [@lm2, @lm1]
192
+ end
193
+ end
194
+
195
+ context "with #all" do
196
+ should "work" do
197
+ @lounge.messages.all(:order => "position").should == [@lm1, @lm2]
198
+ end
199
+
200
+ should "work with conditions" do
201
+ messages = @lounge.messages.all(:body => 'Loungin!', :order => "position")
202
+ messages.should == [@lm1]
203
+ end
204
+
205
+ should "work with order" do
206
+ messages = @lounge.messages.all(:order => 'position desc')
207
+ messages.should == [@lm2, @lm1]
208
+ end
209
+ end
210
+
211
+ context "with :first" do
212
+ should "work" do
213
+ @lounge.messages.find(:first, :order => "position asc").should == @lm1
214
+ end
215
+
216
+ should "work with conditions" do
217
+ message = @lounge.messages.find(:first, :body => 'I love loungin!', :order => "position asc")
218
+ message.should == @lm2
219
+ end
220
+ end
221
+
222
+ context "with #first" do
223
+ should "work" do
224
+ @lounge.messages.first(:order => "position asc").should == @lm1
225
+ end
226
+
227
+ should "work with conditions" do
228
+ message = @lounge.messages.first(:body => 'I love loungin!', :order => "position asc")
229
+ message.should == @lm2
230
+ end
231
+ end
232
+
233
+ context "with :last" do
234
+ should "work" do
235
+ @lounge.messages.find(:last, :order => "position asc").should == @lm2
236
+ end
237
+
238
+ should "work with conditions" do
239
+ message = @lounge.messages.find(:last, :body => 'Loungin!', :order => "position asc")
240
+ message.should == @lm1
241
+ end
242
+ end
243
+
244
+ context "with #last" do
245
+ should "work" do
246
+ @lounge.messages.last(:order => "position asc").should == @lm2
247
+ end
248
+
249
+ should "work with conditions" do
250
+ message = @lounge.messages.last(:body => 'Loungin!', :order => "position asc")
251
+ message.should == @lm1
252
+ end
253
+ end
254
+
255
+ context "with one id" do
256
+ should "work for id in association" do
257
+ @lounge.messages.find(@lm2._id).should == @lm2
258
+ end
259
+
260
+ should "not work for id not in association" do
261
+ lambda {
262
+ @lounge.messages.find!(@hm2._id)
263
+ }.should raise_error(MongoMapper::DocumentNotFound)
264
+ end
265
+ end
266
+
267
+ context "with query options/criteria" do
268
+ should "work with order on association" do
269
+ @lounge.messages.should == [@lm1, @lm2]
270
+ end
271
+
272
+ should "allow overriding the order provided to the association" do
273
+ @lounge.messages.all(:order => 'position').should == [@lm1, @lm2]
274
+ end
275
+
276
+ should "allow using conditions on association" do
277
+ @hall.latest_messages.should == [@hm3, @hm2]
278
+ end
279
+ end
280
+
281
+ context "with multiple ids" do
282
+ should "work for ids in association" do
283
+ messages = @lounge.messages.find(@lm1._id, @lm2._id)
284
+ messages.should == [@lm1, @lm2]
285
+ end
286
+
287
+ should "not work for ids not in association" do
288
+ lambda {
289
+ @lounge.messages.find!(@lm1._id, @lm2._id, @hm2._id)
290
+ }.should raise_error(MongoMapper::DocumentNotFound)
291
+ end
292
+ end
293
+
294
+ context "with #paginate" do
295
+ setup do
296
+ @messages = @hall.messages.paginate(:per_page => 2, :page => 1, :order => 'position asc')
297
+ end
298
+
299
+ should "return total pages" do
300
+ @messages.total_pages.should == 2
301
+ end
302
+
303
+ should "return total entries" do
304
+ @messages.total_entries.should == 3
305
+ end
306
+
307
+ should "return the subject" do
308
+ @messages.should == [@hm1, @hm2]
309
+ end
310
+ end
311
+ end
312
+
313
+ context "extending the association" do
314
+ should "work using a block passed to many" do
315
+ room = Room.new(:name => "Amazing Room")
316
+ messages = room.messages = [
317
+ Enter.new(:body => 'John entered room', :position => 3),
318
+ Chat.new(:body => 'Heyyyoooo!', :position => 4),
319
+ Exit.new(:body => 'John exited room', :position => 5),
320
+ Enter.new(:body => 'Steve entered room', :position => 6),
321
+ Chat.new(:body => 'Anyone there?', :position => 7),
322
+ Exit.new(:body => 'Steve exited room', :position => 8)
323
+ ]
324
+ room.save
325
+ room.messages.older.should == messages[3..5]
326
+ end
327
+
328
+ should "work using many's :extend option" do
329
+ room = Room.new(:name => "Amazing Room")
330
+ accounts = room.accounts = [
331
+ Bot.new(:last_logged_in => 3.weeks.ago),
332
+ User.new(:last_logged_in => nil),
333
+ Bot.new(:last_logged_in => 1.week.ago)
334
+ ]
335
+ room.save
336
+ room.accounts.inactive.should == [accounts[1]]
337
+ end
338
+ end
339
+ end