jnunemaker-mongomapper 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.gitignore +1 -0
  2. data/History +17 -0
  3. data/README.rdoc +6 -3
  4. data/Rakefile +3 -2
  5. data/VERSION +1 -1
  6. data/bin/mmconsole +56 -0
  7. data/lib/mongomapper.rb +48 -17
  8. data/lib/mongomapper/associations.rb +31 -39
  9. data/lib/mongomapper/associations/base.rb +40 -22
  10. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +33 -0
  11. data/lib/mongomapper/associations/belongs_to_proxy.rb +10 -14
  12. data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +34 -0
  13. data/lib/mongomapper/associations/{has_many_embedded_proxy.rb → many_embedded_proxy.rb} +5 -5
  14. data/lib/mongomapper/associations/many_proxy.rb +55 -0
  15. data/lib/mongomapper/associations/proxy.rb +21 -14
  16. data/lib/mongomapper/callbacks.rb +1 -1
  17. data/lib/mongomapper/document.rb +82 -59
  18. data/lib/mongomapper/embedded_document.rb +121 -130
  19. data/lib/mongomapper/finder_options.rb +21 -6
  20. data/lib/mongomapper/key.rb +5 -7
  21. data/lib/mongomapper/observing.rb +1 -41
  22. data/lib/mongomapper/pagination.rb +52 -0
  23. data/lib/mongomapper/rails_compatibility/document.rb +15 -0
  24. data/lib/mongomapper/rails_compatibility/embedded_document.rb +25 -0
  25. data/lib/mongomapper/serialization.rb +1 -1
  26. data/mongomapper.gemspec +62 -36
  27. data/test/NOTE_ON_TESTING +1 -0
  28. data/test/functional/test_associations.rb +485 -0
  29. data/test/{test_callbacks.rb → functional/test_callbacks.rb} +2 -1
  30. data/test/functional/test_document.rb +636 -0
  31. data/test/functional/test_pagination.rb +82 -0
  32. data/test/functional/test_rails_compatibility.rb +31 -0
  33. data/test/functional/test_validations.rb +172 -0
  34. data/test/models.rb +92 -0
  35. data/test/test_helper.rb +5 -0
  36. data/test/{serializers → unit/serializers}/test_json_serializer.rb +0 -0
  37. data/test/unit/test_association_base.rb +131 -0
  38. data/test/unit/test_document.rb +115 -0
  39. data/test/{test_embedded_document.rb → unit/test_embedded_document.rb} +158 -66
  40. data/test/{test_finder_options.rb → unit/test_finder_options.rb} +66 -0
  41. data/test/{test_key.rb → unit/test_key.rb} +13 -1
  42. data/test/unit/test_mongo_id.rb +35 -0
  43. data/test/{test_mongomapper.rb → unit/test_mongomapper.rb} +0 -0
  44. data/test/{test_observing.rb → unit/test_observing.rb} +0 -0
  45. data/test/unit/test_pagination.rb +113 -0
  46. data/test/unit/test_rails_compatibility.rb +34 -0
  47. data/test/{test_serializations.rb → unit/test_serializations.rb} +0 -2
  48. data/test/{test_validations.rb → unit/test_validations.rb} +0 -134
  49. metadata +68 -36
  50. data/lib/mongomapper/associations/has_many_proxy.rb +0 -28
  51. data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +0 -31
  52. data/lib/mongomapper/rails_compatibility.rb +0 -23
  53. data/test/test_associations.rb +0 -149
  54. data/test/test_document.rb +0 -944
  55. data/test/test_rails_compatibility.rb +0 -29
@@ -0,0 +1,52 @@
1
+ module MongoMapper
2
+ module Pagination
3
+ class PaginationProxy < BasicObject
4
+ attr_accessor :subject
5
+ attr_reader :total_entries, :per_page, :current_page
6
+ alias limit per_page
7
+
8
+ def initialize(total_entries, current_page, per_page=nil)
9
+ @total_entries = total_entries.to_i
10
+ self.per_page = per_page
11
+ self.current_page = current_page
12
+ end
13
+
14
+ def total_pages
15
+ (total_entries / per_page.to_f).ceil
16
+ end
17
+
18
+ def out_of_bounds?
19
+ current_page > total_pages
20
+ end
21
+
22
+ def previous_page
23
+ current_page > 1 ? (current_page - 1) : nil
24
+ end
25
+
26
+ def next_page
27
+ current_page < total_pages ? (current_page + 1) : nil
28
+ end
29
+
30
+ def skip
31
+ (current_page - 1) * per_page
32
+ end
33
+ alias offset skip
34
+
35
+ def method_missing(name, *args, &block)
36
+ @subject.send(name, *args, &block)
37
+ end
38
+
39
+ private
40
+ def per_page=(value)
41
+ value = 25 if value.blank?
42
+ @per_page = value.to_i
43
+ end
44
+
45
+ def current_page=(value)
46
+ value = value.to_i
47
+ value = 1 if value < 1
48
+ @current_page = value
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,15 @@
1
+ module MongoMapper
2
+ module RailsCompatibility
3
+ module Document
4
+ def self.included(model)
5
+ model.class_eval do
6
+ alias_method :new_record?, :new?
7
+ end
8
+ end
9
+
10
+ def to_param
11
+ id
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ module MongoMapper
2
+ module RailsCompatibility
3
+ module EmbeddedDocument
4
+ def self.included(model)
5
+ model.class_eval do
6
+ extend ClassMethods
7
+ end
8
+
9
+ class << model
10
+ alias has_many many
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ def column_names
16
+ keys.keys
17
+ end
18
+ end
19
+
20
+ def to_param
21
+ raise "Missing to_param method in #{self.class}. You should implement it to return the unique identifier of this embedded document within a document."
22
+ end
23
+ end
24
+ end
25
+ end
@@ -10,7 +10,7 @@ module MongoMapper #:nodoc:
10
10
  end
11
11
 
12
12
  def serializable_key_names
13
- key_names = @record.send :defined_key_names
13
+ key_names = @record.class.keys.keys
14
14
 
15
15
  if options[:only]
16
16
  options.delete(:except)
data/mongomapper.gemspec CHANGED
@@ -2,12 +2,14 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{mongomapper}
5
- s.version = "0.2.0"
5
+ s.version = "0.3.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["John Nunemaker"]
9
- s.date = %q{2009-07-07}
9
+ s.date = %q{2009-07-28}
10
+ s.default_executable = %q{mmconsole}
10
11
  s.email = %q{nunemaker@gmail.com}
12
+ s.executables = ["mmconsole"]
11
13
  s.extra_rdoc_files = [
12
14
  "LICENSE",
13
15
  "README.rdoc"
@@ -19,14 +21,16 @@ Gem::Specification.new do |s|
19
21
  "README.rdoc",
20
22
  "Rakefile",
21
23
  "VERSION",
24
+ "bin/mmconsole",
22
25
  "lib/mongomapper.rb",
23
26
  "lib/mongomapper/associations.rb",
24
27
  "lib/mongomapper/associations/array_proxy.rb",
25
28
  "lib/mongomapper/associations/base.rb",
29
+ "lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb",
26
30
  "lib/mongomapper/associations/belongs_to_proxy.rb",
27
- "lib/mongomapper/associations/has_many_embedded_proxy.rb",
28
- "lib/mongomapper/associations/has_many_proxy.rb",
29
- "lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb",
31
+ "lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb",
32
+ "lib/mongomapper/associations/many_embedded_proxy.rb",
33
+ "lib/mongomapper/associations/many_proxy.rb",
30
34
  "lib/mongomapper/associations/proxy.rb",
31
35
  "lib/mongomapper/callbacks.rb",
32
36
  "lib/mongomapper/document.rb",
@@ -34,25 +38,36 @@ Gem::Specification.new do |s|
34
38
  "lib/mongomapper/finder_options.rb",
35
39
  "lib/mongomapper/key.rb",
36
40
  "lib/mongomapper/observing.rb",
37
- "lib/mongomapper/rails_compatibility.rb",
41
+ "lib/mongomapper/pagination.rb",
42
+ "lib/mongomapper/rails_compatibility/document.rb",
43
+ "lib/mongomapper/rails_compatibility/embedded_document.rb",
38
44
  "lib/mongomapper/save_with_validation.rb",
39
45
  "lib/mongomapper/serialization.rb",
40
46
  "lib/mongomapper/serializers/json_serializer.rb",
41
47
  "lib/mongomapper/validations.rb",
42
48
  "mongomapper.gemspec",
43
- "test/serializers/test_json_serializer.rb",
44
- "test/test_associations.rb",
45
- "test/test_callbacks.rb",
46
- "test/test_document.rb",
47
- "test/test_embedded_document.rb",
48
- "test/test_finder_options.rb",
49
+ "test/NOTE_ON_TESTING",
50
+ "test/functional/test_associations.rb",
51
+ "test/functional/test_callbacks.rb",
52
+ "test/functional/test_document.rb",
53
+ "test/functional/test_pagination.rb",
54
+ "test/functional/test_rails_compatibility.rb",
55
+ "test/functional/test_validations.rb",
56
+ "test/models.rb",
49
57
  "test/test_helper.rb",
50
- "test/test_key.rb",
51
- "test/test_mongomapper.rb",
52
- "test/test_observing.rb",
53
- "test/test_rails_compatibility.rb",
54
- "test/test_serializations.rb",
55
- "test/test_validations.rb"
58
+ "test/unit/serializers/test_json_serializer.rb",
59
+ "test/unit/test_association_base.rb",
60
+ "test/unit/test_document.rb",
61
+ "test/unit/test_embedded_document.rb",
62
+ "test/unit/test_finder_options.rb",
63
+ "test/unit/test_key.rb",
64
+ "test/unit/test_mongo_id.rb",
65
+ "test/unit/test_mongomapper.rb",
66
+ "test/unit/test_observing.rb",
67
+ "test/unit/test_pagination.rb",
68
+ "test/unit/test_rails_compatibility.rb",
69
+ "test/unit/test_serializations.rb",
70
+ "test/unit/test_validations.rb"
56
71
  ]
57
72
  s.has_rdoc = true
58
73
  s.homepage = %q{http://github.com/jnunemaker/mongomapper}
@@ -62,19 +77,27 @@ Gem::Specification.new do |s|
62
77
  s.rubygems_version = %q{1.3.1}
63
78
  s.summary = %q{Awesome gem for modeling your domain and storing it in mongo}
64
79
  s.test_files = [
65
- "test/serializers/test_json_serializer.rb",
66
- "test/test_associations.rb",
67
- "test/test_callbacks.rb",
68
- "test/test_document.rb",
69
- "test/test_embedded_document.rb",
70
- "test/test_finder_options.rb",
80
+ "test/functional/test_associations.rb",
81
+ "test/functional/test_callbacks.rb",
82
+ "test/functional/test_document.rb",
83
+ "test/functional/test_pagination.rb",
84
+ "test/functional/test_rails_compatibility.rb",
85
+ "test/functional/test_validations.rb",
86
+ "test/models.rb",
71
87
  "test/test_helper.rb",
72
- "test/test_key.rb",
73
- "test/test_mongomapper.rb",
74
- "test/test_observing.rb",
75
- "test/test_rails_compatibility.rb",
76
- "test/test_serializations.rb",
77
- "test/test_validations.rb"
88
+ "test/unit/serializers/test_json_serializer.rb",
89
+ "test/unit/test_association_base.rb",
90
+ "test/unit/test_document.rb",
91
+ "test/unit/test_embedded_document.rb",
92
+ "test/unit/test_finder_options.rb",
93
+ "test/unit/test_key.rb",
94
+ "test/unit/test_mongo_id.rb",
95
+ "test/unit/test_mongomapper.rb",
96
+ "test/unit/test_observing.rb",
97
+ "test/unit/test_pagination.rb",
98
+ "test/unit/test_rails_compatibility.rb",
99
+ "test/unit/test_serializations.rb",
100
+ "test/unit/test_validations.rb"
78
101
  ]
79
102
 
80
103
  if s.respond_to? :specification_version then
@@ -83,21 +106,24 @@ Gem::Specification.new do |s|
83
106
 
84
107
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
85
108
  s.add_runtime_dependency(%q<activesupport>, [">= 0"])
86
- s.add_runtime_dependency(%q<mongodb-mongo>, ["= 0.9"])
87
- s.add_runtime_dependency(%q<jnunemaker-validatable>, ["= 1.7.1"])
109
+ s.add_runtime_dependency(%q<mongodb-mongo>, ["= 0.10.1"])
110
+ s.add_runtime_dependency(%q<jnunemaker-validatable>, ["= 1.7.2"])
111
+ s.add_runtime_dependency(%q<deep_merge>, ["= 0.1.0"])
88
112
  s.add_development_dependency(%q<mocha>, ["= 0.9.4"])
89
113
  s.add_development_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
90
114
  else
91
115
  s.add_dependency(%q<activesupport>, [">= 0"])
92
- s.add_dependency(%q<mongodb-mongo>, ["= 0.9"])
93
- s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.1"])
116
+ s.add_dependency(%q<mongodb-mongo>, ["= 0.10.1"])
117
+ s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.2"])
118
+ s.add_dependency(%q<deep_merge>, ["= 0.1.0"])
94
119
  s.add_dependency(%q<mocha>, ["= 0.9.4"])
95
120
  s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
96
121
  end
97
122
  else
98
123
  s.add_dependency(%q<activesupport>, [">= 0"])
99
- s.add_dependency(%q<mongodb-mongo>, ["= 0.9"])
100
- s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.1"])
124
+ s.add_dependency(%q<mongodb-mongo>, ["= 0.10.1"])
125
+ s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.2"])
126
+ s.add_dependency(%q<deep_merge>, ["= 0.1.0"])
101
127
  s.add_dependency(%q<mocha>, ["= 0.9.4"])
102
128
  s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
103
129
  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,485 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class AssociationsTest < Test::Unit::TestCase
5
+ def setup
6
+ clear_all_collections
7
+ end
8
+
9
+ context "Modularized Polymorphic Many Embedded" do
10
+ should "set associations correctly" do
11
+ fleet_attributes = {
12
+ "name" => "My Fleet",
13
+ "transports" => [
14
+ {"_type" => "TrModels::Ambulance", "license_plate" => "GGG123", "icu" => true},
15
+ {"_type" => "TrModels::Car", "license_plate" => "ABC123", "model" => "VW Golf", "year" => 2001},
16
+ {"_type" => "TrModels::Car", "license_plate" => "DEF123", "model" => "Honda Accord", "year" => 2008},
17
+ ]
18
+ }
19
+
20
+ fleet = TrModels::Fleet.new(fleet_attributes)
21
+ fleet.transports.size.should == 3
22
+ fleet.transports[0].class.should == TrModels::Ambulance
23
+ fleet.transports[0].license_plate.should == "GGG123"
24
+ fleet.transports[0].icu.should be_true
25
+ fleet.transports[1].class.should == TrModels::Car
26
+ fleet.transports[1].license_plate.should == "ABC123"
27
+ fleet.transports[1].model.should == "VW Golf"
28
+ fleet.transports[1].year.should == 2001
29
+ fleet.transports[2].class.should == TrModels::Car
30
+ fleet.transports[2].license_plate.should == "DEF123"
31
+ fleet.transports[2].model.should == "Honda Accord"
32
+ fleet.transports[2].year.should == 2008
33
+ fleet.save.should be_true
34
+
35
+ from_db = TrModels::Fleet.find(fleet.id)
36
+ from_db.transports.size.should == 3
37
+ from_db.transports[0].license_plate.should == "GGG123"
38
+ from_db.transports[0].icu.should be_true
39
+ from_db.transports[1].license_plate.should == "ABC123"
40
+ from_db.transports[1].model.should == "VW Golf"
41
+ from_db.transports[1].year.should == 2001
42
+ from_db.transports[2].license_plate.should == "DEF123"
43
+ from_db.transports[2].model.should == "Honda Accord"
44
+ from_db.transports[2].year.should == 2008
45
+ end
46
+
47
+ should "default reader to empty array" do
48
+ fleet = TrModels::Fleet.new
49
+ fleet.transports.should == []
50
+ end
51
+
52
+ should "allow adding to association like it was an array" do
53
+ fleet = TrModels::Fleet.new
54
+ fleet.transports << TrModels::Car.new
55
+ fleet.transports.push TrModels::Bus.new
56
+ fleet.transports.size.should == 2
57
+ end
58
+
59
+ should "store the association" do
60
+ fleet = TrModels::Fleet.new
61
+ fleet.transports = [TrModels::Car.new("license_plate" => "DCU2013", "model" => "Honda Civic")]
62
+ fleet.save.should be_true
63
+
64
+ from_db = TrModels::Fleet.find(fleet.id)
65
+ from_db.transports.size.should == 1
66
+ from_db.transports[0].license_plate.should == "DCU2013"
67
+ end
68
+
69
+ should "store different associations" do
70
+ fleet = TrModels::Fleet.new
71
+ fleet.transports = [
72
+ TrModels::Car.new("license_plate" => "ABC1223", "model" => "Honda Civic", "year" => 2003),
73
+ TrModels::Bus.new("license_plate" => "XYZ9090", "max_passengers" => 51),
74
+ TrModels::Ambulance.new("license_plate" => "HDD3030", "icu" => true)
75
+ ]
76
+ fleet.save.should be_true
77
+
78
+ from_db = TrModels::Fleet.find(fleet.id)
79
+ from_db.transports.size.should == 3
80
+ from_db.transports[0].license_plate.should == "ABC1223"
81
+ from_db.transports[0].model.should == "Honda Civic"
82
+ from_db.transports[0].year.should == 2003
83
+ from_db.transports[1].license_plate.should == "XYZ9090"
84
+ from_db.transports[1].max_passengers.should == 51
85
+ from_db.transports[2].license_plate.should == "HDD3030"
86
+ from_db.transports[2].icu.should == true
87
+ end
88
+ end
89
+
90
+ context "Polymorphic Many Embedded" do
91
+ should "default reader to empty array" do
92
+ catalog = Catalog.new
93
+ catalog.medias.should == []
94
+ end
95
+
96
+ should "allow adding to association like it was an array" do
97
+ catalog = Catalog.new
98
+ catalog.medias << Video.new
99
+ catalog.medias.push Video.new
100
+ catalog.medias.size.should == 2
101
+ end
102
+
103
+ should "store the association" do
104
+ catalog = Catalog.new
105
+ catalog.medias = [Video.new("file" => "video.mpg", "length" => 3600)]
106
+ catalog.save.should be_true
107
+
108
+ from_db = Catalog.find(catalog.id)
109
+ from_db.medias.size.should == 1
110
+ from_db.medias[0].file.should == "video.mpg"
111
+ end
112
+
113
+ should "store different associations" do
114
+ catalog = Catalog.new
115
+ catalog.medias = [
116
+ Video.new("file" => "video.mpg", "length" => 3600),
117
+ Music.new("file" => "music.mp3", "bitrate" => "128kbps"),
118
+ Image.new("file" => "image.png", "width" => 800, "height" => 600)
119
+ ]
120
+ catalog.save.should be_true
121
+
122
+ from_db = Catalog.find(catalog.id)
123
+ from_db.medias.size.should == 3
124
+ from_db.medias[0].file.should == "video.mpg"
125
+ from_db.medias[0].length.should == 3600
126
+ from_db.medias[1].file.should == "music.mp3"
127
+ from_db.medias[1].bitrate.should == "128kbps"
128
+ from_db.medias[2].file.should == "image.png"
129
+ from_db.medias[2].width.should == 800
130
+ from_db.medias[2].height.should == 600
131
+ end
132
+ end
133
+
134
+ context "Polymorphic Belongs To" do
135
+ should "default to nil" do
136
+ status = Status.new
137
+ status.target.should be_nil
138
+ end
139
+
140
+ should "store the association" do
141
+ status = Status.new
142
+ project = Project.new(:name => "mongomapper")
143
+ status.target = project
144
+ status.save.should be_true
145
+
146
+ from_db = Status.find(status.id)
147
+ from_db.target.should_not be_nil
148
+ from_db.target_id.should == project.id
149
+ from_db.target_type.should == "Project"
150
+ from_db.target.name.should == "mongomapper"
151
+ end
152
+
153
+ should "unset the association" do
154
+ status = Status.new
155
+ project = Project.new(:name => "mongomapper")
156
+ status.target = project
157
+ status.save.should be_true
158
+
159
+ from_db = Status.find(status.id)
160
+ from_db.target = nil
161
+ from_db.target_type.should be_nil
162
+ from_db.target_id.should be_nil
163
+ from_db.target.should be_nil
164
+ end
165
+ end
166
+
167
+ context "Belongs To" do
168
+ should "default to nil" do
169
+ status = Status.new
170
+ status.project.should be_nil
171
+ end
172
+
173
+ should "store the association" do
174
+ status = Status.new
175
+ project = Project.new(:name => "mongomapper")
176
+ status.project = project
177
+ status.save.should be_true
178
+
179
+ from_db = Status.find(status.id)
180
+ from_db.project.should_not be_nil
181
+ from_db.project.name.should == "mongomapper"
182
+ end
183
+
184
+ should "unset the association" do
185
+ status = Status.new
186
+ project = Project.new(:name => "mongomapper")
187
+ status.project = project
188
+ status.save.should be_true
189
+
190
+ from_db = Status.find(status.id)
191
+ from_db.project = nil
192
+ from_db.project.should be_nil
193
+ end
194
+ end
195
+
196
+ context "Many documents" do
197
+ should "default reader to empty array" do
198
+ project = Project.new
199
+ project.statuses.should == []
200
+ end
201
+
202
+ should "allow adding to association like it was an array" do
203
+ project = Project.new
204
+ project.statuses << Status.new
205
+ project.statuses.push Status.new
206
+ project.statuses.size.should == 2
207
+ end
208
+
209
+ should "store the association" do
210
+ project = Project.new
211
+ project.statuses = [Status.new("name" => "ready")]
212
+ project.save.should be_true
213
+
214
+ from_db = Project.find(project.id)
215
+ from_db.statuses.size.should == 1
216
+ from_db.statuses[0].name.should == "ready"
217
+ end
218
+
219
+ context "Finding scoped to association" do
220
+ setup do
221
+ @project1 = Project.new(:name => 'Project 1')
222
+ @brand_new = Status.create(:name => 'New')
223
+ @complete = Status.create(:name => 'Complete')
224
+ @project1.statuses = [@brand_new, @complete]
225
+ @project1.save
226
+
227
+ @project2 = Project.create(:name => 'Project 2')
228
+ @in_progress = Status.create(:name => 'In Progress')
229
+ @archived = Status.create(:name => 'Archived')
230
+ @another_complete = Status.create(:name => 'Complete')
231
+ @project2.statuses = [@in_progress, @archived, @another_complete]
232
+ @project2.save
233
+ end
234
+
235
+ context "with :all" do
236
+ should "work" do
237
+ @project1.statuses.find(:all).should == [@brand_new, @complete]
238
+ end
239
+
240
+ should "work with conditions" do
241
+ statuses = @project1.statuses.find(:all, :conditions => {'name' => 'Complete'})
242
+ statuses.should == [@complete]
243
+ end
244
+
245
+ should "work with order" do
246
+ statuses = @project1.statuses.find(:all, :order => 'name asc')
247
+ statuses.should == [@complete, @brand_new]
248
+ end
249
+ end
250
+
251
+ context "with #all" do
252
+ should "work" do
253
+ @project1.statuses.all.should == [@brand_new, @complete]
254
+ end
255
+
256
+ should "work with conditions" do
257
+ statuses = @project1.statuses.all(:conditions => {'name' => 'Complete'})
258
+ statuses.should == [@complete]
259
+ end
260
+
261
+ should "work with order" do
262
+ statuses = @project1.statuses.all(:order => 'name asc')
263
+ statuses.should == [@complete, @brand_new]
264
+ end
265
+ end
266
+
267
+ context "with :first" do
268
+ should "work" do
269
+ @project1.statuses.find(:first).should == @brand_new
270
+ end
271
+
272
+ should "work with conditions" do
273
+ status = @project1.statuses.find(:first, :conditions => {:name => 'Complete'})
274
+ status.should == @complete
275
+ end
276
+ end
277
+
278
+ context "with #first" do
279
+ should "work" do
280
+ @project1.statuses.first.should == @brand_new
281
+ end
282
+
283
+ should "work with conditions" do
284
+ status = @project1.statuses.first(:conditions => {:name => 'Complete'})
285
+ status.should == @complete
286
+ end
287
+ end
288
+
289
+ context "with :last" do
290
+ should "work" do
291
+ @project1.statuses.find(:last).should == @complete
292
+ end
293
+
294
+ should "work with conditions" do
295
+ status = @project1.statuses.find(:last, :conditions => {:name => 'New'})
296
+ status.should == @brand_new
297
+ end
298
+ end
299
+
300
+ context "with #last" do
301
+ should "work" do
302
+ @project1.statuses.last.should == @complete
303
+ end
304
+
305
+ should "work with conditions" do
306
+ status = @project1.statuses.last(:conditions => {:name => 'New'})
307
+ status.should == @brand_new
308
+ end
309
+ end
310
+
311
+ context "with one id" do
312
+ should "work for id in association" do
313
+ @project1.statuses.find(@complete.id).should == @complete
314
+ end
315
+
316
+ should "not work for id not in association" do
317
+ lambda {
318
+ @project1.statuses.find(@archived.id)
319
+ }.should raise_error(MongoMapper::DocumentNotFound)
320
+ end
321
+ end
322
+
323
+ context "with multiple ids" do
324
+ should "work for ids in association" do
325
+ statuses = @project1.statuses.find(@brand_new.id, @complete.id)
326
+ statuses.should == [@brand_new, @complete]
327
+ end
328
+
329
+ should "not work for ids not in association" do
330
+ lambda {
331
+ @project1.statuses.find(@brand_new.id, @complete.id, @archived.id)
332
+ }.should raise_error(MongoMapper::DocumentNotFound)
333
+ end
334
+ end
335
+
336
+ context "with #paginate" do
337
+ setup do
338
+ @statuses = @project2.statuses.paginate(:per_page => 2, :page => 1)
339
+ end
340
+
341
+ should "return total pages" do
342
+ @statuses.total_pages.should == 2
343
+ end
344
+
345
+ should "return total entries" do
346
+ @statuses.total_entries.should == 3
347
+ end
348
+
349
+ should "return the subject" do
350
+ @statuses.should == [@in_progress, @archived]
351
+ end
352
+ end
353
+ end
354
+ end
355
+
356
+ context "Many embedded documents" do
357
+ should "allow adding to association like it was an array" do
358
+ project = Project.new
359
+ project.addresses << Address.new
360
+ project.addresses.push Address.new
361
+ project.addresses.size.should == 2
362
+ end
363
+
364
+ should "be embedded in document on save" do
365
+ sb = Address.new(:city => 'South Bend', :state => 'IN')
366
+ chi = Address.new(:city => 'Chicago', :state => 'IL')
367
+ project = Project.new
368
+ project.addresses << sb
369
+ project.addresses << chi
370
+ project.save
371
+
372
+ from_db = Project.find(project.id)
373
+ from_db.addresses.size.should == 2
374
+ from_db.addresses[0].should == sb
375
+ from_db.addresses[1].should == chi
376
+ end
377
+
378
+ should "allow embedding arbitrarily deep" do
379
+ @document = Class.new do
380
+ include MongoMapper::Document
381
+ key :person, Person
382
+ end
383
+ @document.collection.clear
384
+
385
+ meg = Person.new(:name => "Meg")
386
+ meg.child = Person.new(:name => "Steve")
387
+ meg.child.child = Person.new(:name => "Linda")
388
+
389
+ doc = @document.new(:person => meg)
390
+ doc.save
391
+
392
+ from_db = @document.find(doc.id)
393
+ from_db.person.name.should == 'Meg'
394
+ from_db.person.child.name.should == 'Steve'
395
+ from_db.person.child.child.name.should == 'Linda'
396
+ end
397
+
398
+ should "allow assignment of 'many' embedded documents using a hash" do
399
+ person_attributes = {
400
+ "name" => "Mr. Pet Lover",
401
+ "pets" => [
402
+ {"name" => "Jimmy", "species" => "Cocker Spainel"},
403
+ {"name" => "Sasha", "species" => "Siberian Husky"},
404
+ ]
405
+ }
406
+
407
+ pet_lover = RealPerson.new(person_attributes)
408
+ pet_lover.name.should == "Mr. Pet Lover"
409
+ pet_lover.pets[0].name.should == "Jimmy"
410
+ pet_lover.pets[0].species.should == "Cocker Spainel"
411
+ pet_lover.pets[1].name.should == "Sasha"
412
+ pet_lover.pets[1].species.should == "Siberian Husky"
413
+ pet_lover.save.should be_true
414
+
415
+ from_db = RealPerson.find(pet_lover.id)
416
+ from_db.name.should == "Mr. Pet Lover"
417
+ from_db.pets[0].name.should == "Jimmy"
418
+ from_db.pets[0].species.should == "Cocker Spainel"
419
+ from_db.pets[1].name.should == "Sasha"
420
+ from_db.pets[1].species.should == "Siberian Husky"
421
+ end
422
+
423
+ should "allow saving embedded documents in 'many' embedded documents" do
424
+ @document = Class.new do
425
+ include MongoMapper::Document
426
+ many :people
427
+ end
428
+ @document.collection.clear
429
+
430
+ meg = Person.new(:name => "Meg")
431
+ sparky = Pet.new(:name => "Sparky", :species => "Dog")
432
+ koda = Pet.new(:name => "Koda", :species => "Dog")
433
+
434
+ doc = @document.new
435
+
436
+ meg.pets << sparky
437
+ meg.pets << koda
438
+
439
+ doc.people << meg
440
+ doc.save
441
+
442
+ from_db = @document.find(doc.id)
443
+ from_db.people.first.name.should == "Meg"
444
+ from_db.people.first.pets.should_not == []
445
+ from_db.people.first.pets.first.name.should == "Sparky"
446
+ from_db.people.first.pets.first.species.should == "Dog"
447
+ from_db.people.first.pets[1].name.should == "Koda"
448
+ from_db.people.first.pets[1].species.should == "Dog"
449
+ end
450
+ end
451
+
452
+ context "Changing association class names" do
453
+ should "work for many and belongs to" do
454
+ class AwesomeUser
455
+ include MongoMapper::Document
456
+ many :posts, :class_name => 'AssociationsTest::AwesomePost', :foreign_key => :creator_id
457
+ end
458
+
459
+ class AwesomeTag
460
+ include MongoMapper::EmbeddedDocument
461
+ key :name, String
462
+ belongs_to :post, :class_name => 'AssociationsTest::AwesomeUser'
463
+ end
464
+
465
+ class AwesomePost
466
+ include MongoMapper::Document
467
+ belongs_to :creator, :class_name => 'AssociationsTest::AwesomeUser'
468
+ many :tags, :class_name => 'AssociationsTest::AwesomeTag', :foreign_key => :post_id
469
+ end
470
+
471
+ AwesomeUser.collection.clear
472
+ AwesomePost.collection.clear
473
+
474
+ user = AwesomeUser.create
475
+ tag1 = AwesomeTag.new(:name => 'awesome')
476
+ tag2 = AwesomeTag.new(:name => 'grand')
477
+ post1 = AwesomePost.create(:creator => user, :tags => [tag1])
478
+ post2 = AwesomePost.create(:creator => user, :tags => [tag2])
479
+ user.posts.should == [post1, post2]
480
+
481
+ post1_from_db = AwesomePost.find(post1.id)
482
+ post1_from_db.tags.should == [tag1]
483
+ end
484
+ end
485
+ end