dm-mongo-adapter 0.2.0.pre1

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 (65) hide show
  1. data/.gitignore +9 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +130 -0
  4. data/Rakefile +36 -0
  5. data/TODO +33 -0
  6. data/VERSION.yml +5 -0
  7. data/bin/console +31 -0
  8. data/dm-mongo-adapter.gemspec +154 -0
  9. data/lib/mongo_adapter.rb +71 -0
  10. data/lib/mongo_adapter/adapter.rb +255 -0
  11. data/lib/mongo_adapter/aggregates.rb +21 -0
  12. data/lib/mongo_adapter/conditions.rb +100 -0
  13. data/lib/mongo_adapter/embedded_model.rb +187 -0
  14. data/lib/mongo_adapter/embedded_resource.rb +134 -0
  15. data/lib/mongo_adapter/embedments/one_to_many.rb +139 -0
  16. data/lib/mongo_adapter/embedments/one_to_one.rb +53 -0
  17. data/lib/mongo_adapter/embedments/relationship.rb +258 -0
  18. data/lib/mongo_adapter/migrations.rb +45 -0
  19. data/lib/mongo_adapter/model.rb +89 -0
  20. data/lib/mongo_adapter/model/embedment.rb +215 -0
  21. data/lib/mongo_adapter/modifier.rb +85 -0
  22. data/lib/mongo_adapter/query.rb +252 -0
  23. data/lib/mongo_adapter/query/java_script.rb +145 -0
  24. data/lib/mongo_adapter/resource.rb +147 -0
  25. data/lib/mongo_adapter/types/date.rb +28 -0
  26. data/lib/mongo_adapter/types/date_time.rb +28 -0
  27. data/lib/mongo_adapter/types/db_ref.rb +65 -0
  28. data/lib/mongo_adapter/types/discriminator.rb +32 -0
  29. data/lib/mongo_adapter/types/object_id.rb +72 -0
  30. data/lib/mongo_adapter/types/objects.rb +31 -0
  31. data/script/performance.rb +260 -0
  32. data/spec/legacy/README +6 -0
  33. data/spec/legacy/adapter_shared_spec.rb +299 -0
  34. data/spec/legacy/adapter_spec.rb +174 -0
  35. data/spec/legacy/associations_spec.rb +140 -0
  36. data/spec/legacy/embedded_resource_spec.rb +157 -0
  37. data/spec/legacy/embedments_spec.rb +177 -0
  38. data/spec/legacy/modifier_spec.rb +81 -0
  39. data/spec/legacy/property_spec.rb +51 -0
  40. data/spec/legacy/spec_helper.rb +3 -0
  41. data/spec/legacy/sti_spec.rb +53 -0
  42. data/spec/lib/cleanup_models.rb +32 -0
  43. data/spec/lib/raw_connections.rb +11 -0
  44. data/spec/public/embedded_collection_spec.rb +61 -0
  45. data/spec/public/embedded_resource_spec.rb +220 -0
  46. data/spec/public/model/embedment_spec.rb +186 -0
  47. data/spec/public/model_spec.rb +37 -0
  48. data/spec/public/resource_spec.rb +564 -0
  49. data/spec/public/shared/model_embedments_spec.rb +338 -0
  50. data/spec/public/shared/object_id_shared_spec.rb +56 -0
  51. data/spec/public/types/df_ref_spec.rb +6 -0
  52. data/spec/public/types/discriminator_spec.rb +118 -0
  53. data/spec/public/types/embedded_array_spec.rb +55 -0
  54. data/spec/public/types/embedded_hash_spec.rb +83 -0
  55. data/spec/public/types/object_id_spec.rb +6 -0
  56. data/spec/rcov.opts +6 -0
  57. data/spec/semipublic/embedded_model_spec.rb +43 -0
  58. data/spec/semipublic/model/embedment_spec.rb +42 -0
  59. data/spec/semipublic/resource_spec.rb +70 -0
  60. data/spec/spec.opts +4 -0
  61. data/spec/spec_helper.rb +45 -0
  62. data/tasks/spec.rake +37 -0
  63. data/tasks/yard.rake +9 -0
  64. data/tasks/yardstick.rake +21 -0
  65. metadata +215 -0
@@ -0,0 +1,338 @@
1
+ # The share specs contained herein are very slightly modified versions of
2
+ # those found in dm-core/spec/public/model/relationship_spec.rb
3
+
4
+ share_examples_for 'A singular embedment reader' do
5
+ it { @car.should respond_to(@name) }
6
+
7
+ describe 'reader' do
8
+ describe 'when there is no associated resource' do
9
+ it 'should return nil when there is no query' do
10
+ @car.__send__(@name).should be_nil
11
+ end
12
+
13
+ it 'should return nil when there is a query' do
14
+ @car.__send__(@name, :name => '__nothing__').should be_nil
15
+ end
16
+ end # when there is no associated resource
17
+
18
+ describe 'when there is an associated resource' do
19
+ before(:all) do
20
+ @expected = @model.new
21
+ @car.__send__("#{@name}=", @expected)
22
+ end
23
+
24
+ describe 'without a query' do
25
+ it 'should return an EmbeddedResource' do
26
+ returned = @car.__send__(@name)
27
+ returned.should be_kind_of(DataMapper::Mongo::EmbeddedResource)
28
+ end
29
+
30
+ it 'should return the correct EmbeddedResource' do
31
+ @car.__send__(@name).should == @expected
32
+ end
33
+ end
34
+
35
+ describe 'with a query' do
36
+ it 'should return a EmbeddedResource' do
37
+ returned = @car.__send__(@name, :name => @expected.name)
38
+ returned.should be_kind_of(DataMapper::Mongo::EmbeddedResource)
39
+ end
40
+
41
+ it 'should return the correct EmbeddedResource' do
42
+ @car.__send__(@name, :name => @expected.name).should == @expected
43
+ end
44
+ end
45
+ end # when there is an associated resource
46
+
47
+ end # reader
48
+ end # A singular embedment reader
49
+
50
+ share_examples_for 'A singular embedment writer' do
51
+ it { @car.should respond_to("#{@name}=") }
52
+
53
+ describe 'writer' do
54
+ describe 'when setting the wrong kind of target' do
55
+ it 'should raise an ArgumentError' do
56
+ calling = lambda { @car.__send__("#{@name}=", Object.new) }
57
+ calling.should raise_error(ArgumentError)
58
+ end
59
+ end
60
+
61
+ describe 'when setting an EmbeddedResource' do
62
+ before(:all) do
63
+ @expected = @model.new
64
+ @return = @car.__send__("#{@name}=", @expected)
65
+ end
66
+
67
+ it 'should return the expected EmbeddedResource' do
68
+ @return.should equal(@expected)
69
+ end
70
+
71
+ it 'should set the EmbeddedResource' do
72
+ @car.__send__(@name).should equal(@expected)
73
+ end
74
+
75
+ it 'should relate the associated EmbeddedResource' do
76
+ @expected.parent.should == @car
77
+ end
78
+
79
+ it 'should persist the Resource' do
80
+ @car.save.should be_true
81
+ @car.model.get(*@car.key).__send__(@name).should == @expected
82
+ end
83
+ end # when setting an EmbeddedResource
84
+
85
+ describe 'when setting a Hash' do
86
+ before(:all) do
87
+ @expected = @model.new(:name => 'Name')
88
+ @return = @car.__send__("#{@name}=", { :name => 'Name' })
89
+ end
90
+
91
+ it 'should return the expected EmbeddedResource' do
92
+ @return.should == @expected
93
+ end
94
+
95
+ it 'should set the EmbeddedResource' do
96
+ @car.__send__(@name).should equal(@return)
97
+ end
98
+
99
+ it 'should relate the associated EmbeddedResource' do
100
+ @car.__send__(@name).parent.should == @car
101
+ end
102
+
103
+ it 'should persist the Resource' do
104
+ @car.save.should be_true
105
+ @car.model.get(*@car.key).__send__(@name).should == @expected
106
+ end
107
+ end # when setting a Hash
108
+
109
+ describe 'when setting nil' do
110
+ before(:all) do
111
+ @car.__send__("#{@name}=", @model.new)
112
+ @return = @car.__send__("#{@name}=", nil)
113
+ end
114
+
115
+ it 'should return nil' do
116
+ @return.should be_nil
117
+ end
118
+
119
+ it 'should set nil' do
120
+ @car.__send__(@name).should be_nil
121
+ end
122
+
123
+ it 'should persist as nil' do
124
+ @car.save.should be_true
125
+ @car.model.get(*@car.key).__send__(@name).should be_nil
126
+ end
127
+ end # when setting nil
128
+
129
+ describe 'when changing the EmbeddedResource' do
130
+ before(:all) do
131
+ @car.__send__("#{@name}=", @model.new)
132
+ @return = @car.__send__("#{@name}=", @expected = @model.new)
133
+ end
134
+
135
+ it 'should return the expected EmbeddedResource' do
136
+ @return.should equal(@expected)
137
+ end
138
+
139
+ it 'should set the EmbeddedResource' do
140
+ @car.__send__(@name).should equal(@return)
141
+ end
142
+
143
+ it 'should relate the associated EmbeddedResource' do
144
+ @car.__send__(@name).parent.should == @car
145
+ end
146
+
147
+ it 'should persist the Resource' do
148
+ @car.save.should be_true
149
+ @car.model.get(*@car.key).__send__(@name).should == @expected
150
+ end
151
+ end # when changing the EmbeddedResource
152
+
153
+ end # writer
154
+ end # A singular embedment writer
155
+
156
+ share_examples_for 'A many embedment reader' do
157
+ it { @car.should respond_to(@name) }
158
+
159
+ describe 'reader' do
160
+ describe 'when there are no child resources and the source is saved' do
161
+ before(:all) do
162
+ @car.save.should be_true
163
+ @return = @car.__send__(@name)
164
+ end
165
+
166
+ it 'should return a Collection' do
167
+ @return.should be_kind_of(
168
+ DataMapper::Mongo::Embedments::OneToMany::Collection)
169
+ end
170
+
171
+ it 'should return an empty Collection' do
172
+ @return.should be_empty
173
+ end
174
+ end # when there is no child resource and the source is saved
175
+
176
+ describe 'when there are no child resources and the source is not saved' do
177
+ before(:all) do
178
+ @return = @car.__send__(@name)
179
+ end
180
+
181
+ it 'should return a Collection' do
182
+ @return.should be_kind_of(
183
+ DataMapper::Mongo::Embedments::OneToMany::Collection)
184
+ end
185
+
186
+ it 'should return an empty Collection' do
187
+ @return.should be_empty
188
+ end
189
+ end # when there is no child resource and the source is not save
190
+
191
+ describe 'when there is a child resource' do
192
+ before(:all) do
193
+ @expected = @model.new
194
+ @car.__send__("#{@name}=", [ @expected ])
195
+ @return = @car.__send__(@name)
196
+ end
197
+
198
+ it 'should return a Collection' do
199
+ @return.should be_kind_of(
200
+ DataMapper::Mongo::Embedments::OneToMany::Collection)
201
+ end
202
+
203
+ it 'should return the expected resources' do
204
+ @return.should == [ @expected ]
205
+ end
206
+ end # when there is a child resource
207
+
208
+ end # reader
209
+ end # A many embedment reader
210
+
211
+ share_examples_for 'A many embedment writer' do
212
+ it { @car.should respond_to("#{@name}=") }
213
+
214
+ describe 'writer' do
215
+ describe 'when setting an Array of the wrong kind of target' do
216
+ it 'should raise an ArgumentError' do
217
+ calling = lambda { @car.__send__("#{@name}=", [Object.new]) }
218
+ calling.should raise_error(ArgumentError)
219
+ end
220
+ end # when setting an Array of the wrong kind of target
221
+
222
+ describe 'when setting an Array of EmbeddedResources' do
223
+ before(:all) do
224
+ @expected = [ @model.new ]
225
+ @return = @car.__send__("#{@name}=", @expected)
226
+ end
227
+
228
+ it 'should return the expected Collection' do
229
+ @return.should == @expected
230
+ end
231
+
232
+ it 'should set the Collection' do
233
+ @car.__send__(@name).should == @expected
234
+ @car.__send__(@name).zip(@expected) do |value, expected|
235
+ value.should equal(expected)
236
+ end
237
+ end
238
+
239
+ it 'should relate the associated Collection' do
240
+ @expected.each { |resource| resource.parent.should == @car }
241
+ end
242
+
243
+ it 'should persist the Collection' do
244
+ @car.save.should be_true
245
+ @car.model.get(*@car.key).__send__(@name).should == @expected
246
+ end
247
+
248
+ it 'should persist the associated EmbeddedResources' do
249
+ @car.save.should be_true
250
+ @expected.each { |resource| resource.should be_saved }
251
+ end
252
+ end # when setting an Array of EmbeddedResources
253
+
254
+ describe 'when setting an Array of Hashes' do
255
+ before(:all) do
256
+ @expected = [ @model.new(:name => 'Name') ]
257
+ @return = @car.__send__("#{@name}=", [{ :name => 'Name' }])
258
+ end
259
+
260
+ it 'should return the expected Collection' do
261
+ @return.should == @expected
262
+ end
263
+
264
+ it 'should set the Collection' do
265
+ @car.__send__(@name).should == @expected
266
+ @car.__send__(@name).zip(@expected) do |value, expected|
267
+ value.should == expected
268
+ end
269
+ end
270
+
271
+ it 'should relate the associated Collection' do
272
+ @return.each { |resource| resource.parent.should == @car }
273
+ end
274
+
275
+ it 'should persist the Collection' do
276
+ @car.save.should be_true
277
+ @car.model.get(*@car.key).__send__(@name).should == @expected
278
+ end
279
+
280
+ it 'should persist the associated EmbeddedResources' do
281
+ @car.save.should be_true
282
+ @return.each { |resource| resource.should be_saved }
283
+ end
284
+ end # when setting an Array of Hashes
285
+
286
+ describe 'when setting an empty collection' do
287
+ before :all do
288
+ @car.__send__("#{@name}=", [ @model.new ])
289
+ @return = @car.__send__("#{@name}=", [])
290
+ end
291
+
292
+ it 'should return a Collection' do
293
+ @return.should be_kind_of(
294
+ DataMapper::Mongo::Embedments::OneToMany::Collection)
295
+ end
296
+
297
+ it 'should set a empty Collection' do
298
+ @car.__send__(@name).should be_empty
299
+ end
300
+
301
+ it 'should persist as an empty collection' do
302
+ @car.save.should be_true
303
+ @car.model.get(*@car.key).__send__(@name).should be_empty
304
+ end
305
+ end # when setting an empty collection
306
+
307
+ describe 'when changing an associated collection' do
308
+ before(:all) do
309
+ @car.__send__("#{@name}=", [ @model.new ])
310
+ @expected = [ @model.new ]
311
+ @return = @car.__send__("#{@name}=", @expected)
312
+ end
313
+
314
+ it 'should return the expected Resource' do
315
+ @return.should == @expected
316
+ end
317
+
318
+ it 'should set the Resource' do
319
+ @car.__send__(@name).should == @expected
320
+ end
321
+
322
+ it 'should relate the associated Resource' do
323
+ @expected.each { |resource| resource.parent.should == @car }
324
+ end
325
+
326
+ it 'should persist the Resource' do
327
+ @car.save.should be_true
328
+ @car.model.get(*@car.key).__send__(@name).should == @expected
329
+ end
330
+
331
+ it 'should persist the associated Resource' do
332
+ @car.save.should be_true
333
+ @expected.each { |resource| resource.should be_saved }
334
+ end
335
+ end # when setting an associated collection
336
+
337
+ end #writer
338
+ end # A many embedment writer
@@ -0,0 +1,56 @@
1
+ share_examples_for 'An ObjectID Type' do
2
+
3
+ describe '.load' do
4
+ it 'should return nil when given nil' do
5
+ @type_class.load(nil, nil).should be_nil
6
+ end
7
+
8
+ it 'should return the argument when given a string' do
9
+ loaded = @type_class.load('avalue', nil)
10
+ loaded.should == 'avalue'
11
+ end
12
+
13
+ it 'should return a string when given a Mongo::ObjectID' do
14
+ mongo_id = ::Mongo::ObjectID.new
15
+ loaded = @type_class.load(mongo_id, nil)
16
+ loaded.should be_kind_of(String)
17
+ loaded.should == mongo_id.to_s
18
+ end
19
+
20
+ it 'should raise an error when given anything else' do
21
+ [ 0, 1, Object.new, true, false, [], {} ].each do |value|
22
+ lambda {
23
+ @type_class.load(value, nil)
24
+ }.should raise_error(ArgumentError)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '.dump' do
30
+ it 'should return nil when given nil' do
31
+ @type_class.dump(nil, nil).should be_nil
32
+ end
33
+
34
+ it 'should return a Mongo::ObjectID when given a string' do
35
+ mongo_id = ::Mongo::ObjectID.new
36
+ dumped = @type_class.dump(mongo_id.to_s, nil)
37
+ dumped.should be_kind_of(::Mongo::ObjectID)
38
+ dumped.to_s.should == mongo_id.to_s
39
+ end
40
+
41
+ it 'should return the argument when given a Mongo::ObjectID' do
42
+ mongo_id = ::Mongo::ObjectID.new
43
+ dumped = @type_class.dump(mongo_id, nil)
44
+ dumped.should == mongo_id
45
+ end
46
+
47
+ it 'should raise an error when given anything else' do
48
+ [ 0, 1, Object.new, true, false, [], {} ].each do |value|
49
+ lambda {
50
+ @type_class.dump(value, nil)
51
+ }.should raise_error(ArgumentError)
52
+ end
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,6 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
+
3
+ describe DataMapper::Mongo::Types::DBRef do
4
+ before(:all) { @type_class = DataMapper::Mongo::Types::DBRef }
5
+ it_should_behave_like 'An ObjectID Type'
6
+ end
@@ -0,0 +1,118 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
+
3
+ describe DataMapper::Mongo::Types::Discriminator do
4
+ before :all do
5
+ class Article
6
+ include DataMapper::Mongo::Resource
7
+
8
+ property :id, ObjectID
9
+ property :title, String, :required => true
10
+ property :type, Discriminator
11
+ end
12
+
13
+ class Announcement < Article; end
14
+ class Release < Announcement; end
15
+
16
+ Article.all.destroy!
17
+
18
+ @article_model = Article
19
+ @announcement_model = Announcement
20
+ @release_model = Release
21
+ end
22
+
23
+ it 'should typecast to a Model' do
24
+ @article_model.properties[:type].typecast('Release').should equal(@release_model)
25
+ end
26
+
27
+ describe 'Model#new' do
28
+ describe 'when provided a String discriminator in the attributes' do
29
+ before :all do
30
+ @resource = @article_model.new(:type => 'Release')
31
+ end
32
+
33
+ it 'should return a Resource' do
34
+ @resource.should be_kind_of(DataMapper::Resource)
35
+ end
36
+
37
+ it 'should be an descendant instance' do
38
+ @resource.should be_instance_of(Release)
39
+ end
40
+ end
41
+
42
+ describe 'when provided a Class discriminator in the attributes' do
43
+ before :all do
44
+ @resource = @article_model.new(:type => Release)
45
+ end
46
+
47
+ it 'should return a Resource' do
48
+ @resource.should be_kind_of(DataMapper::Resource)
49
+ end
50
+
51
+ it 'should be an descendant instance' do
52
+ @resource.should be_instance_of(Release)
53
+ end
54
+ end
55
+
56
+ describe 'when not provided a discriminator in the attributes' do
57
+ before :all do
58
+ @resource = @article_model.new
59
+ end
60
+
61
+ it 'should return a Resource' do
62
+ @resource.should be_kind_of(DataMapper::Resource)
63
+ end
64
+
65
+ it 'should be a base model instance' do
66
+ @resource.should be_instance_of(@article_model)
67
+ end
68
+ end
69
+ end
70
+
71
+ describe 'Model#descendants' do
72
+ it 'should set the descendants for the grandparent model' do
73
+ @article_model.descendants.to_a.should == [ @article_model, @announcement_model, @release_model ]
74
+ end
75
+
76
+ it 'should set the descendants for the parent model' do
77
+ @announcement_model.descendants.to_a.should == [ @announcement_model, @release_model ]
78
+ end
79
+
80
+ it 'should set the descendants for the child model' do
81
+ @release_model.descendants.to_a.should == [ @release_model ]
82
+ end
83
+ end
84
+
85
+ describe 'Model#default_scope' do
86
+ it 'should set the default scope for the grandparent model' do
87
+ @article_model.default_scope[:type].should equal(@article_model.descendants)
88
+ end
89
+
90
+ it 'should set the default scope for the parent model' do
91
+ @announcement_model.default_scope[:type].should equal(@announcement_model.descendants)
92
+ end
93
+
94
+ it 'should set the default scope for the child model' do
95
+ @release_model.default_scope[:type].should equal(@release_model.descendants)
96
+ end
97
+ end
98
+
99
+ before :all do
100
+ @announcement = @announcement_model.create(:title => 'Announcement')
101
+ end
102
+
103
+ it 'should persist the type' do
104
+ @announcement.model.get(*@announcement.key).type.should equal(@announcement_model)
105
+ end
106
+
107
+ it 'should be retrieved as an instance of the correct class' do
108
+ @announcement.model.get(*@announcement.key).should be_instance_of(@announcement_model)
109
+ end
110
+
111
+ it 'should include descendants in finders' do
112
+ @article_model.first.should eql(@announcement)
113
+ end
114
+
115
+ it 'should not include ancestors' do
116
+ @release_model.first.should be_nil
117
+ end
118
+ end