mongo_mapper-unstable 2010.1.6 → 2010.1.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/VERSION +1 -1
  2. data/lib/mongo_mapper/descendant_appends.rb +44 -0
  3. data/lib/mongo_mapper/document.rb +54 -98
  4. data/lib/mongo_mapper/embedded_document.rb +28 -348
  5. data/lib/mongo_mapper/finder_options.rb +15 -33
  6. data/lib/mongo_mapper/plugins/associations/base.rb +121 -0
  7. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +28 -0
  8. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +23 -0
  9. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  10. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +49 -0
  11. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  12. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  13. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  14. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  15. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  16. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  17. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +66 -0
  18. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  19. data/lib/mongo_mapper/plugins/associations.rb +104 -0
  20. data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
  21. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  22. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  23. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  24. data/lib/mongo_mapper/plugins/equality.rb +11 -0
  25. data/lib/mongo_mapper/plugins/identity_map.rb +66 -0
  26. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  27. data/lib/mongo_mapper/plugins/keys.rb +295 -0
  28. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  29. data/lib/mongo_mapper/plugins/pagination.rb +85 -0
  30. data/lib/mongo_mapper/plugins/rails.rb +45 -0
  31. data/lib/mongo_mapper/plugins/serialization.rb +109 -0
  32. data/lib/mongo_mapper/plugins/validations.rb +48 -0
  33. data/lib/mongo_mapper/plugins.rb +19 -0
  34. data/lib/mongo_mapper/support.rb +36 -15
  35. data/lib/mongo_mapper.rb +23 -22
  36. data/performance/read_write.rb +52 -0
  37. data/specs.watchr +23 -2
  38. data/test/functional/associations/test_belongs_to_proxy.rb +1 -1
  39. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +58 -39
  40. data/test/functional/associations/test_many_embedded_proxy.rb +103 -69
  41. data/test/functional/test_dirty.rb +1 -1
  42. data/test/functional/test_document.rb +25 -25
  43. data/test/functional/test_embedded_document.rb +66 -63
  44. data/test/functional/test_identity_map.rb +233 -0
  45. data/test/functional/test_modifiers.rb +14 -0
  46. data/test/functional/test_string_id_compatibility.rb +4 -4
  47. data/test/functional/test_validations.rb +13 -0
  48. data/test/models.rb +0 -39
  49. data/test/test_helper.rb +8 -2
  50. data/test/unit/associations/test_base.rb +1 -1
  51. data/test/unit/associations/test_proxy.rb +3 -3
  52. data/test/unit/test_descendant_appends.rb +71 -0
  53. data/test/unit/test_document.rb +35 -46
  54. data/test/unit/test_embedded_document.rb +218 -271
  55. data/test/unit/{test_key.rb → test_keys.rb} +0 -0
  56. data/test/unit/test_pagination.rb +10 -2
  57. data/test/unit/test_plugins.rb +42 -0
  58. data/test/unit/test_rails.rb +123 -0
  59. data/test/unit/{test_serializations.rb → test_serialization.rb} +0 -0
  60. data/test/unit/test_support.rb +10 -6
  61. data/test/unit/test_time_zones.rb +2 -2
  62. metadata +44 -31
  63. data/lib/mongo_mapper/associations/base.rb +0 -119
  64. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +0 -26
  65. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +0 -21
  66. data/lib/mongo_mapper/associations/collection.rb +0 -19
  67. data/lib/mongo_mapper/associations/in_array_proxy.rb +0 -137
  68. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -26
  69. data/lib/mongo_mapper/associations/many_documents_proxy.rb +0 -115
  70. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +0 -31
  71. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +0 -54
  72. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +0 -11
  73. data/lib/mongo_mapper/associations/one_proxy.rb +0 -64
  74. data/lib/mongo_mapper/associations/proxy.rb +0 -116
  75. data/lib/mongo_mapper/associations.rb +0 -78
  76. data/lib/mongo_mapper/callbacks.rb +0 -61
  77. data/lib/mongo_mapper/dirty.rb +0 -117
  78. data/lib/mongo_mapper/key.rb +0 -36
  79. data/lib/mongo_mapper/mongo_mapper.rb +0 -125
  80. data/lib/mongo_mapper/pagination.rb +0 -66
  81. data/lib/mongo_mapper/rails_compatibility/document.rb +0 -15
  82. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +0 -28
  83. data/lib/mongo_mapper/serialization.rb +0 -54
  84. data/lib/mongo_mapper/serializers/json_serializer.rb +0 -48
  85. data/lib/mongo_mapper/validations.rb +0 -39
  86. data/test/functional/test_rails_compatibility.rb +0 -25
data/lib/mongo_mapper.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  # if Gem is defined i'll assume you are using rubygems and lock specific versions
2
4
  # call me crazy but a plain old require will just get the latest version you have installed
3
5
  # so i want to make sure that if you are using gems you do in fact have the correct versions
@@ -98,29 +100,28 @@ module MongoMapper
98
100
  end
99
101
  end
100
102
 
101
- require 'mongo_mapper/support'
102
- require 'mongo_mapper/callbacks'
103
103
  require 'mongo_mapper/finder_options'
104
- require 'mongo_mapper/dirty'
104
+ require 'mongo_mapper/support'
105
+ require 'mongo_mapper/descendant_appends'
106
+
105
107
  require 'mongo_mapper/dynamic_finder'
106
108
  require 'mongo_mapper/key'
107
- require 'mongo_mapper/pagination'
108
- require 'mongo_mapper/serialization'
109
- require 'mongo_mapper/validations'
110
- require 'mongo_mapper/rails_compatibility/document'
111
- require 'mongo_mapper/rails_compatibility/embedded_document'
109
+
110
+ require 'mongo_mapper/plugins'
111
+ require 'mongo_mapper/plugins/associations'
112
+ require 'mongo_mapper/plugins/callbacks'
113
+ require 'mongo_mapper/plugins/clone'
114
+ require 'mongo_mapper/plugins/descendants'
115
+ require 'mongo_mapper/plugins/dirty'
116
+ require 'mongo_mapper/plugins/equality'
117
+ require 'mongo_mapper/plugins/identity_map'
118
+ require 'mongo_mapper/plugins/inspect'
119
+ require 'mongo_mapper/plugins/keys'
120
+ require 'mongo_mapper/plugins/logger'
121
+ require 'mongo_mapper/plugins/pagination'
122
+ require 'mongo_mapper/plugins/rails'
123
+ require 'mongo_mapper/plugins/serialization'
124
+ require 'mongo_mapper/plugins/validations'
125
+
112
126
  require 'mongo_mapper/embedded_document'
113
- require 'mongo_mapper/document'
114
- require 'mongo_mapper/associations'
115
- require 'mongo_mapper/associations/base'
116
- require 'mongo_mapper/associations/proxy'
117
- require 'mongo_mapper/associations/collection'
118
- require 'mongo_mapper/associations/many_documents_proxy'
119
- require 'mongo_mapper/associations/belongs_to_proxy'
120
- require 'mongo_mapper/associations/belongs_to_polymorphic_proxy'
121
- require 'mongo_mapper/associations/many_polymorphic_proxy'
122
- require 'mongo_mapper/associations/many_embedded_proxy'
123
- require 'mongo_mapper/associations/many_embedded_polymorphic_proxy'
124
- require 'mongo_mapper/associations/many_documents_as_proxy'
125
- require 'mongo_mapper/associations/one_proxy'
126
- require 'mongo_mapper/associations/in_array_proxy'
127
+ require 'mongo_mapper/document'
@@ -0,0 +1,52 @@
1
+ # The purpose of this is to check finding, initializing,
2
+ # and creating objects (typecasting times/dates and booleans).
3
+
4
+ require 'pp'
5
+ require 'benchmark'
6
+ require 'rubygems'
7
+
8
+ # to test with slow version just do this:
9
+ # gem 'mongo_mapper', '0.6.10'
10
+ # and comment out this:
11
+ $:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
12
+
13
+ require 'mongo_mapper'
14
+
15
+ MongoMapper.database = 'testing'
16
+
17
+ class Foo
18
+ include MongoMapper::Document
19
+ key :approved, Boolean
20
+ key :count, Integer
21
+ key :approved_at, Time
22
+ key :expire_on, Date
23
+ timestamps!
24
+ end
25
+ Foo.collection.remove
26
+
27
+ Benchmark.bm(5) do |x|
28
+ ids = []
29
+ x.report("write") do
30
+ 1000.times { |i| ids << Foo.create(:count => 0, :approved => true, :approved_at => Time.now, :expire_on => Date.today).id }
31
+ end
32
+
33
+ x.report("read ") do
34
+ ids.each { |id| Foo.first(:id => id) }
35
+ end
36
+ end
37
+
38
+ # I was get something like this on my puny macbook air:
39
+ # user system total real
40
+ # write 4.810000 0.090000 4.900000 ( 5.039949)
41
+ # read 2.730000 0.070000 2.800000 ( 2.990749)
42
+ #
43
+ #
44
+ # After these commits:
45
+ #
46
+ # * http://github.com/jnunemaker/mongomapper/commit/e5091fa140d5fae2721017b53027092233694ee5
47
+ # * http://github.com/jnunemaker/mongomapper/commit/c22bbde4fa1cfbc310d79cb0e50203310ffb03d1
48
+ #
49
+ # I'm now getting something like this:
50
+ # user system total real
51
+ # write 1.660000 0.050000 1.710000 ( 1.752676)
52
+ # read 1.060000 0.050000 1.110000 ( 1.263429)
data/specs.watchr CHANGED
@@ -1,6 +1,27 @@
1
+ def growl(title, msg, img)
2
+ %x{growlnotify -m #{ msg.inspect} -t #{title.inspect} --image ~/.watchr/#{img}.png}
3
+ end
4
+
5
+ def form_growl_message(str)
6
+ results = str.split("\n").last
7
+ if results =~ /[1-9]\s(failure|error)s?/
8
+ growl "Test Results", "#{results}", "fail"
9
+ elsif results != ""
10
+ growl "Test Results", "#{results}", "pass"
11
+ end
12
+ end
13
+
1
14
  def run(cmd)
2
15
  puts(cmd)
3
- system(cmd)
16
+ output = ""
17
+ IO.popen(cmd) do |com|
18
+ com.each_char do |c|
19
+ print c
20
+ output << c
21
+ $stdout.flush
22
+ end
23
+ end
24
+ form_growl_message output
4
25
  end
5
26
 
6
27
  def run_test_file(file)
@@ -17,7 +38,7 @@ end
17
38
 
18
39
  watch('test/test_helper\.rb') { system('clear'); run_all_tests }
19
40
  watch('test/.*/test_.*\.rb') { |m| system('clear'); run_test_file(m[0]) }
20
- watch('lib/.*') { |m| related_test_files(m[0]).each { |file| system('clear'); run_test_file(file) } }
41
+ watch('lib/.*') { |m| related_test_files(m[0]).each { |file| run_test_file(file) } }
21
42
 
22
43
  # Ctrl-\
23
44
  Signal.trap('QUIT') do
@@ -72,7 +72,7 @@ class BelongsToProxyTest < Test::Unit::TestCase
72
72
  setup do
73
73
  Property.key :thing_id, ObjectId
74
74
  Property.belongs_to :thing, :dependent => :destroy
75
- Thing.has_many :properties
75
+ Thing.many :properties
76
76
 
77
77
  @thing = Thing.create(:name => "Tree")
78
78
  @property1 = Property.create
@@ -21,30 +21,49 @@ class ManyEmbeddedPolymorphicProxyTest < Test::Unit::TestCase
21
21
 
22
22
  should "be able to replace the association" do
23
23
  catalog = Catalog.new
24
- catalog.medias = [Video.new("file" => "video.mpg", "length" => 3600)]
24
+ catalog.medias = [Video.new('file' => 'video.mpg', 'length' => 3600)]
25
25
  catalog.save.should be_true
26
26
 
27
27
  catalog = catalog.reload
28
28
  catalog.medias.size.should == 1
29
- catalog.medias[0].file.should == "video.mpg"
29
+ catalog.medias[0].file.should == 'video.mpg'
30
30
  end
31
-
31
+
32
+ context "count" do
33
+ should "default to 0" do
34
+ Catalog.new.medias.count.should == 0
35
+ end
36
+
37
+ should 'return correct count if any are embedded' do
38
+ catalog = Catalog.new
39
+ catalog.medias = [
40
+ Video.new('file' => 'video.mpg', 'length' => 3600),
41
+ Music.new('file' => 'music.mp3', 'bitrate' => '128kbps'),
42
+ Image.new('file' => 'image.png', 'width' => 800, 'height' => 600)
43
+ ]
44
+ catalog.medias.count.should == 3
45
+ catalog.save.should be_true
46
+ catalog.reload
47
+ catalog.medias.count.should == 3
48
+ end
49
+ end
50
+
32
51
  should "store different associations" do
33
52
  catalog = Catalog.new
34
53
  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)
54
+ Video.new('file' => 'video.mpg', 'length' => 3600),
55
+ Music.new('file' => 'music.mp3', 'bitrate' => '128kbps'),
56
+ Image.new('file' => 'image.png', 'width' => 800, 'height' => 600)
38
57
  ]
39
58
  catalog.save.should be_true
40
59
 
41
60
  catalog = catalog.reload
42
61
  catalog.medias.size.should == 3
43
- catalog.medias[0].file.should == "video.mpg"
62
+ catalog.medias[0].file.should == 'video.mpg'
44
63
  catalog.medias[0].length.should == 3600
45
- catalog.medias[1].file.should == "music.mp3"
64
+ catalog.medias[1].file.should == 'music.mp3'
46
65
  catalog.medias[1].bitrate.should == "128kbps"
47
- catalog.medias[2].file.should == "image.png"
66
+ catalog.medias[2].file.should == 'image.png'
48
67
  catalog.medias[2].width.should == 800
49
68
  catalog.medias[2].height.should == 600
50
69
  end
@@ -52,38 +71,38 @@ class ManyEmbeddedPolymorphicProxyTest < Test::Unit::TestCase
52
71
  context "With modularized models" do
53
72
  should "set associations correctly" do
54
73
  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},
74
+ 'name' => 'My Fleet',
75
+ 'transports' => [
76
+ {'_type' => 'TrModels::Ambulance', 'license_plate' => 'GGG123', 'icu' => true},
77
+ {'_type' => 'TrModels::Car', 'license_plate' => 'ABC123', 'model' => 'VW Golf', 'year' => 2001},
78
+ {'_type' => 'TrModels::Car', 'license_plate' => 'DEF123', 'model' => 'Honda Accord', 'year' => 2008},
60
79
  ]
61
80
  }
62
81
 
63
82
  fleet = TrModels::Fleet.new(fleet_attributes)
64
83
  fleet.transports.size.should == 3
65
84
  fleet.transports[0].class.should == TrModels::Ambulance
66
- fleet.transports[0].license_plate.should == "GGG123"
85
+ fleet.transports[0].license_plate.should == 'GGG123'
67
86
  fleet.transports[0].icu.should be_true
68
87
  fleet.transports[1].class.should == TrModels::Car
69
- fleet.transports[1].license_plate.should == "ABC123"
70
- fleet.transports[1].model.should == "VW Golf"
88
+ fleet.transports[1].license_plate.should == 'ABC123'
89
+ fleet.transports[1].model.should == 'VW Golf'
71
90
  fleet.transports[1].year.should == 2001
72
91
  fleet.transports[2].class.should == TrModels::Car
73
- fleet.transports[2].license_plate.should == "DEF123"
74
- fleet.transports[2].model.should == "Honda Accord"
92
+ fleet.transports[2].license_plate.should == 'DEF123'
93
+ fleet.transports[2].model.should == 'Honda Accord'
75
94
  fleet.transports[2].year.should == 2008
76
95
  fleet.save.should be_true
77
96
 
78
97
  fleet = fleet.reload
79
98
  fleet.transports.size.should == 3
80
- fleet.transports[0].license_plate.should == "GGG123"
99
+ fleet.transports[0].license_plate.should == 'GGG123'
81
100
  fleet.transports[0].icu.should be_true
82
- fleet.transports[1].license_plate.should == "ABC123"
83
- fleet.transports[1].model.should == "VW Golf"
101
+ fleet.transports[1].license_plate.should == 'ABC123'
102
+ fleet.transports[1].model.should == 'VW Golf'
84
103
  fleet.transports[1].year.should == 2001
85
- fleet.transports[2].license_plate.should == "DEF123"
86
- fleet.transports[2].model.should == "Honda Accord"
104
+ fleet.transports[2].license_plate.should == 'DEF123'
105
+ fleet.transports[2].model.should == 'Honda Accord'
87
106
  fleet.transports[2].year.should == 2008
88
107
  end
89
108
 
@@ -101,31 +120,31 @@ class ManyEmbeddedPolymorphicProxyTest < Test::Unit::TestCase
101
120
 
102
121
  should "be able to replace the association" do
103
122
  fleet = TrModels::Fleet.new
104
- fleet.transports = [TrModels::Car.new("license_plate" => "DCU2013", "model" => "Honda Civic")]
123
+ fleet.transports = [TrModels::Car.new('license_plate' => 'DCU2013', 'model' => 'Honda Civic')]
105
124
  fleet.save.should be_true
106
125
 
107
126
  fleet = fleet.reload
108
127
  fleet.transports.size.should == 1
109
- fleet.transports[0].license_plate.should == "DCU2013"
128
+ fleet.transports[0].license_plate.should == 'DCU2013'
110
129
  end
111
130
 
112
131
  should "store different associations" do
113
132
  fleet = TrModels::Fleet.new
114
133
  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)
134
+ TrModels::Car.new('license_plate' => 'ABC1223', 'model' => 'Honda Civic', 'year' => 2003),
135
+ TrModels::Bus.new('license_plate' => 'XYZ9090', 'max_passengers' => 51),
136
+ TrModels::Ambulance.new('license_plate' => 'HDD3030', 'icu' => true)
118
137
  ]
119
138
  fleet.save.should be_true
120
139
 
121
140
  fleet = fleet.reload
122
141
  fleet.transports.size.should == 3
123
- fleet.transports[0].license_plate.should == "ABC1223"
124
- fleet.transports[0].model.should == "Honda Civic"
142
+ fleet.transports[0].license_plate.should == 'ABC1223'
143
+ fleet.transports[0].model.should == 'Honda Civic'
125
144
  fleet.transports[0].year.should == 2003
126
- fleet.transports[1].license_plate.should == "XYZ9090"
145
+ fleet.transports[1].license_plate.should == 'XYZ9090'
127
146
  fleet.transports[1].max_passengers.should == 51
128
- fleet.transports[2].license_plate.should == "HDD3030"
147
+ fleet.transports[2].license_plate.should == 'HDD3030'
129
148
  fleet.transports[2].icu.should == true
130
149
  end
131
150
  end
@@ -134,9 +153,9 @@ class ManyEmbeddedPolymorphicProxyTest < Test::Unit::TestCase
134
153
  should "work using a block passed to many" do
135
154
  catalog = Catalog.new
136
155
  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)
156
+ Video.new('file' => 'video.mpg', 'length' => 3600, :visible => true),
157
+ Music.new('file' => 'music.mp3', 'bitrate' => '128kbps', :visible => true),
158
+ Image.new('file' => 'image.png', 'width' => 800, 'height' => 600, :visible => false)
140
159
  ]
141
160
  catalog.save
142
161
  catalog.medias.visible.should == [medias[0], medias[1]]
@@ -145,9 +164,9 @@ class ManyEmbeddedPolymorphicProxyTest < Test::Unit::TestCase
145
164
  should "work using many's :extend option" do
146
165
  fleet = TrModels::Fleet.new
147
166
  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)
167
+ TrModels::Car.new('license_plate' => 'ABC1223', 'model' => 'Honda Civic', 'year' => 2003, :purchased_on => 2.years.ago.to_date),
168
+ TrModels::Bus.new('license_plate' => 'XYZ9090', 'max_passengers' => 51, :purchased_on => 3.years.ago.to_date),
169
+ TrModels::Ambulance.new('license_plate' => 'HDD3030', 'icu' => true, :purchased_on => 1.year.ago.to_date)
151
170
  ]
152
171
  fleet.save
153
172
  fleet.transports.to_be_replaced.should == [transports[1]]
@@ -3,120 +3,139 @@ require 'models'
3
3
 
4
4
  class ManyEmbeddedProxyTest < Test::Unit::TestCase
5
5
  def setup
6
- Project.collection.remove
7
- RealPerson.collection.remove
6
+ @comment_class = EDoc do
7
+ key :name, String
8
+ key :body, String
9
+ end
10
+ @post_class = Doc do
11
+ key :title, String
12
+ end
13
+ @post_class.many :comments, :class => @comment_class
14
+
15
+ @pet_class = EDoc do
16
+ key :name, String
17
+ end
18
+ @person_class = EDoc do
19
+ key :name, String
20
+ end
21
+ @person_class.key :child, @person_class
22
+ @person_class.many :pets, :class => @pet_class
23
+
24
+ @owner_class = Doc do
25
+ key :name, String
26
+ end
27
+ @owner_class.many :pets, :class => @pet_class
8
28
  end
9
29
 
10
30
  should "default reader to empty array" do
11
- Project.new.addresses.should == []
31
+ @post_class.new.comments.should == []
12
32
  end
13
33
 
14
34
  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
35
+ post = @post_class.new
36
+ post.comments << @comment_class.new
37
+ post.comments.push @comment_class.new
38
+ post.comments.size.should == 2
19
39
  end
20
40
 
21
41
  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
42
+ frank = @comment_class.new(:name => 'Frank', :body => 'Hi!')
43
+ bill = @comment_class.new(:name => 'Bill', :body => 'Hi!')
44
+ post = @post_class.new
45
+ post.comments << frank
46
+ post.comments << bill
47
+ post.save
28
48
 
29
- project.reload
30
- project.addresses.size.should == 2
31
- project.addresses[0].should == sb
32
- project.addresses[1].should == chi
49
+ post.reload
50
+ post.comments.size.should == 2
51
+ post.comments[0].should == frank
52
+ post.comments[1].should == bill
33
53
  end
34
54
 
35
55
  should "allow embedding arbitrarily deep" do
36
- @document = Doc do
37
- key :person, Person
38
- end
56
+ @klass = Doc()
57
+ @klass.key :person, @person_class
39
58
 
40
- meg = Person.new(:name => "Meg")
41
- meg.child = Person.new(:name => "Steve")
42
- meg.child.child = Person.new(:name => "Linda")
59
+ meg = @person_class.new(:name => 'Meg')
60
+ meg.child = @person_class.new(:name => 'Steve')
61
+ meg.child.child = @person_class.new(:name => 'Linda')
43
62
 
44
- doc = @document.new(:person => meg)
63
+ doc = @klass.new(:person => meg)
45
64
  doc.save
46
-
47
65
  doc.reload
66
+
48
67
  doc.person.name.should == 'Meg'
49
68
  doc.person.child.name.should == 'Steve'
50
69
  doc.person.child.child.name.should == 'Linda'
51
70
  end
52
71
 
53
- should "allow assignment of 'many' embedded documents using a hash" do
72
+ should "allow assignment of many embedded documents using a hash" do
54
73
  person_attributes = {
55
- "name" => "Mr. Pet Lover",
56
- "pets" => [
57
- {"name" => "Jimmy", "species" => "Cocker Spainel"},
58
- {"name" => "Sasha", "species" => "Siberian Husky"},
74
+ 'name' => 'Mr. Pet Lover',
75
+ 'pets' => [
76
+ {'name' => 'Jimmy', 'species' => 'Cocker Spainel'},
77
+ {'name' => 'Sasha', 'species' => 'Siberian Husky'},
59
78
  ]
60
79
  }
61
80
 
62
- pet_lover = RealPerson.new(person_attributes)
63
- pet_lover.name.should == "Mr. Pet Lover"
64
- pet_lover.pets[0].name.should == "Jimmy"
65
- pet_lover.pets[0].species.should == "Cocker Spainel"
66
- pet_lover.pets[1].name.should == "Sasha"
67
- pet_lover.pets[1].species.should == "Siberian Husky"
68
- pet_lover.save.should be_true
69
-
70
- pet_lover.reload
71
- pet_lover.name.should == "Mr. Pet Lover"
72
- pet_lover.pets[0].name.should == "Jimmy"
73
- pet_lover.pets[0].species.should == "Cocker Spainel"
74
- pet_lover.pets[1].name.should == "Sasha"
75
- pet_lover.pets[1].species.should == "Siberian Husky"
81
+ owner = @owner_class.new(person_attributes)
82
+ owner.name.should == 'Mr. Pet Lover'
83
+ owner.pets[0].name.should == 'Jimmy'
84
+ owner.pets[0].species.should == 'Cocker Spainel'
85
+ owner.pets[1].name.should == 'Sasha'
86
+ owner.pets[1].species.should == 'Siberian Husky'
87
+
88
+ owner.save.should be_true
89
+ owner.reload
90
+
91
+ owner.name.should == 'Mr. Pet Lover'
92
+ owner.pets[0].name.should == 'Jimmy'
93
+ owner.pets[0].species.should == 'Cocker Spainel'
94
+ owner.pets[1].name.should == 'Sasha'
95
+ owner.pets[1].species.should == 'Siberian Husky'
76
96
  end
77
97
 
78
98
  context "embedding many embedded documents" do
79
99
  setup do
80
- @document = Doc do
81
- many :people
82
- end
100
+ @klass = Doc()
101
+ @klass.many :people, :class => @person_class
83
102
  end
84
103
 
85
104
  should "persist all embedded documents" do
86
- meg = Person.new(:name => "Meg")
87
- sparky = Pet.new(:name => "Sparky", :species => "Dog")
88
- koda = Pet.new(:name => "Koda", :species => "Dog")
89
-
90
- doc = @document.new
91
- meg.pets << sparky
92
- meg.pets << koda
105
+ meg = @person_class.new(:name => 'Meg', :pets => [
106
+ @pet_class.new(:name => 'Sparky', :species => 'Dog'),
107
+ @pet_class.new(:name => 'Koda', :species => 'Dog')
108
+ ])
109
+
110
+ doc = @klass.new
93
111
  doc.people << meg
94
112
  doc.save
95
-
96
113
  doc.reload
97
- doc.people.first.name.should == "Meg"
114
+
115
+ doc.people.first.name.should == 'Meg'
98
116
  doc.people.first.pets.should_not == []
99
- doc.people.first.pets.first.name.should == "Sparky"
100
- doc.people.first.pets.first.species.should == "Dog"
101
- doc.people.first.pets[1].name.should == "Koda"
102
- doc.people.first.pets[1].species.should == "Dog"
117
+ doc.people.first.pets.first.name.should == 'Sparky'
118
+ doc.people.first.pets.first.species.should == 'Dog'
119
+ doc.people.first.pets[1].name.should == 'Koda'
120
+ doc.people.first.pets[1].species.should == 'Dog'
103
121
  end
104
122
 
105
123
  should "create a reference to the root document for all embedded documents before save" do
106
- meg = Person.new(:name => "Meg")
107
- sparky = Pet.new(:name => "Sparky", :species => "Dog")
108
- doc = @document.new
124
+ doc = @klass.new
125
+ meg = @person_class.new(:name => 'Meg')
126
+ pet = @pet_class.new(:name => 'Sparky', :species => 'Dog')
127
+
109
128
  doc.people << meg
110
- meg.pets << sparky
129
+ meg.pets << pet
111
130
 
112
131
  doc.people.first._root_document.should == doc
113
132
  doc.people.first.pets.first._root_document.should == doc
114
133
  end
115
134
 
116
135
  should "create a reference to the root document for all embedded documents" do
117
- sparky = Pet.new(:name => "Sparky", :species => "Dog")
118
- meg = Person.new(:name => "Meg", :pets => [sparky])
119
- doc = @document.new
136
+ sparky = @pet_class.new(:name => 'Sparky', :species => 'Dog')
137
+ meg = @person_class.new(:name => 'Meg', :pets => [sparky])
138
+ doc = @klass.new
120
139
  doc.people << meg
121
140
  doc.save
122
141
 
@@ -127,13 +146,28 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
127
146
  end
128
147
 
129
148
  should "allow finding by id" do
130
- sparky = Pet.new(:name => "Sparky", :species => "Dog")
131
- meg = Person.new(:name => "Meg", :pets => [sparky])
149
+ sparky = @pet_class.new(:name => 'Sparky', :species => 'Dog')
150
+ meg = @owner_class.create(:name => 'Meg', :pets => [sparky])
132
151
 
133
152
  meg.pets.find(sparky._id).should == sparky # oid
134
153
  meg.pets.find(sparky.id.to_s).should == sparky # string
135
154
  end
136
155
 
156
+ context "count" do
157
+ should "default to 0" do
158
+ @owner_class.new.pets.count.should == 0
159
+ end
160
+
161
+ should "return correct count if any are embedded" do
162
+ owner = @owner_class.new(:name => 'Meg')
163
+ owner.pets = [@pet_class.new, @pet_class.new]
164
+ owner.pets.count.should == 2
165
+ owner.save
166
+ owner.reload
167
+ owner.pets.count.should == 2
168
+ end
169
+ end
170
+
137
171
  context "extending the association" do
138
172
  setup do
139
173
  @address_class = EDoc do
@@ -112,7 +112,7 @@ class DirtyTest < Test::Unit::TestCase
112
112
  should "be hash of keys with values of changes if there are changes" do
113
113
  doc = @document.new
114
114
  doc.phrase = 'A penny saved is a penny earned.'
115
- doc.changes.should == {'phrase' => [nil, 'A penny saved is a penny earned.']}
115
+ doc.changes['phrase'].should == [nil, 'A penny saved is a penny earned.']
116
116
  end
117
117
  end
118
118