djsun-mongo_mapper 0.5.5.3 → 0.5.6.1

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.
@@ -220,7 +220,6 @@ module MongoMapper
220
220
  attrs = HashWithIndifferentAccess.new
221
221
 
222
222
  embedded_keys.each do |key|
223
- puts key.inspect
224
223
  attrs[key.name] = read_attribute(key.name).try(:attributes)
225
224
  end
226
225
 
@@ -1,54 +1,14 @@
1
1
  module MongoMapper
2
2
  class FinderOptions
3
- attr_reader :options
4
-
5
- def self.to_mongo_criteria(conditions, parent_key=nil)
6
- criteria = {}
7
- conditions.each_pair do |field, value|
8
- field = field_normalized(field)
9
- case value
10
- when Array
11
- operator_present = field.to_s =~ /^\$/
12
- criteria[field] = if operator_present
13
- value
14
- else
15
- {'$in' => value}
16
- end
17
- when Hash
18
- criteria[field] = to_mongo_criteria(value, field)
19
- else
20
- criteria[field] = value
21
- end
22
- end
23
-
24
- criteria
25
- end
26
-
27
- def self.to_mongo_options(options)
28
- options = options.dup
29
- {
30
- :fields => to_mongo_fields(options.delete(:fields) || options.delete(:select)),
31
- :skip => (options.delete(:skip) || options.delete(:offset) || 0).to_i,
32
- :limit => (options.delete(:limit) || 0).to_i,
33
- :sort => options.delete(:sort) || to_mongo_sort(options.delete(:order))
34
- }
35
- end
36
-
37
- def self.field_normalized(field)
38
- if field.to_s == 'id'
39
- :_id
40
- else
41
- field
42
- end
43
- end
44
-
45
3
  OptionKeys = [:fields, :select, :skip, :offset, :limit, :sort, :order]
46
4
 
47
- def initialize(options)
5
+ attr_reader :model, :options
6
+
7
+ def initialize(model, options)
48
8
  raise ArgumentError, "FinderOptions must be a hash" unless options.is_a?(Hash)
9
+ options.symbolize_keys!
49
10
 
50
- options = options.symbolize_keys
51
- @options, @conditions = {}, options.delete(:conditions) || {}
11
+ @model, @options, @conditions = model, {}, options.delete(:conditions) || {}
52
12
 
53
13
  options.each_pair do |key, value|
54
14
  if OptionKeys.include?(key)
@@ -60,11 +20,11 @@ module MongoMapper
60
20
  end
61
21
 
62
22
  def criteria
63
- self.class.to_mongo_criteria(@conditions)
23
+ to_mongo_criteria(model, @conditions)
64
24
  end
65
25
 
66
26
  def options
67
- self.class.to_mongo_options(@options)
27
+ to_mongo_options(model, @options)
68
28
  end
69
29
 
70
30
  def to_a
@@ -72,7 +32,56 @@ module MongoMapper
72
32
  end
73
33
 
74
34
  private
75
- def self.to_mongo_fields(fields)
35
+ def to_mongo_criteria(model, conditions, parent_key=nil)
36
+ criteria = {}
37
+ add_sci_scope(model, criteria)
38
+
39
+ conditions.each_pair do |field, value|
40
+ field = field_normalized(field)
41
+ case value
42
+ when Array
43
+ operator_present = field.to_s =~ /^\$/
44
+ criteria[field] = if operator_present
45
+ value
46
+ else
47
+ {'$in' => value}
48
+ end
49
+ when Hash
50
+ criteria[field] = to_mongo_criteria(model, value, field)
51
+ else
52
+ criteria[field] = value
53
+ end
54
+ end
55
+
56
+ criteria
57
+ end
58
+
59
+ def field_normalized(field)
60
+ if field.to_s == 'id'
61
+ :_id
62
+ else
63
+ field
64
+ end
65
+ end
66
+
67
+ # adds _type single collection inheritance scope for models that need it
68
+ def add_sci_scope(model, criteria)
69
+ if model.single_collection_inherited?
70
+ criteria[:_type] = model.to_s
71
+ end
72
+ end
73
+
74
+ def to_mongo_options(model, options)
75
+ options = options.dup
76
+ {
77
+ :fields => to_mongo_fields(options.delete(:fields) || options.delete(:select)),
78
+ :skip => (options.delete(:skip) || options.delete(:offset) || 0).to_i,
79
+ :limit => (options.delete(:limit) || 0).to_i,
80
+ :sort => options.delete(:sort) || to_mongo_sort(options.delete(:order))
81
+ }
82
+ end
83
+
84
+ def to_mongo_fields(fields)
76
85
  return if fields.blank?
77
86
 
78
87
  if fields.is_a?(String)
@@ -82,13 +91,13 @@ module MongoMapper
82
91
  end
83
92
  end
84
93
 
85
- def self.to_mongo_sort(sort)
94
+ def to_mongo_sort(sort)
86
95
  return if sort.blank?
87
96
  pieces = sort.split(',')
88
97
  pieces.map { |s| to_mongo_sort_piece(s) }
89
98
  end
90
99
 
91
- def self.to_mongo_sort_piece(str)
100
+ def to_mongo_sort_piece(str)
92
101
  field, direction = str.strip.split(' ')
93
102
  direction ||= 'ASC'
94
103
  direction = direction.upcase == 'ASC' ? 1 : -1
@@ -51,5 +51,4 @@ module MongoMapper #:nodoc:
51
51
  end
52
52
  end
53
53
 
54
- dir = Pathname(__FILE__).dirname.expand_path + 'serializers'
55
- require dir + 'json_serializer'
54
+ require 'mongo_mapper/serializers/json_serializer'
@@ -18,7 +18,9 @@ module MongoMapper
18
18
  option :scope
19
19
 
20
20
  def valid?(instance)
21
- doc = instance.class.find(:first, :conditions => {self.attribute => instance[attribute]}.merge(scope_conditions(instance)), :limit => 1)
21
+ value = instance[attribute]
22
+ return true if allow_blank && value.blank?
23
+ doc = instance.class.first({self.attribute => value}.merge(scope_conditions(instance)))
22
24
  doc.nil? || instance.id == doc.id
23
25
  end
24
26
 
data/mongo_mapper.gemspec CHANGED
@@ -1,16 +1,17 @@
1
1
  # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongo_mapper}
8
- s.version = "0.5.5"
8
+ s.version = "0.5.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["John Nunemaker"]
12
- s.date = %q{2009-10-16}
12
+ s.date = %q{2009-10-22}
13
13
  s.default_executable = %q{mmconsole}
14
+ s.description = %q{Awesome gem for modeling your domain and storing it in mongo}
14
15
  s.email = %q{nunemaker@gmail.com}
15
16
  s.executables = ["mmconsole"]
16
17
  s.extra_rdoc_files = [
@@ -94,7 +95,6 @@ Gem::Specification.new do |s|
94
95
  s.homepage = %q{http://github.com/jnunemaker/mongomapper}
95
96
  s.rdoc_options = ["--charset=UTF-8"]
96
97
  s.require_paths = ["lib"]
97
- s.rubyforge_project = %q{mongomapper}
98
98
  s.rubygems_version = %q{1.3.5}
99
99
  s.summary = %q{Awesome gem for modeling your domain and storing it in mongo}
100
100
  s.test_files = [
@@ -143,7 +143,7 @@ Gem::Specification.new do |s|
143
143
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
144
144
  s.add_runtime_dependency(%q<activesupport>, [">= 2.3"])
145
145
  s.add_runtime_dependency(%q<mongo>, ["= 0.15.1"])
146
- s.add_runtime_dependency(%q<jnunemaker-validatable>, ["= 1.7.4"])
146
+ s.add_runtime_dependency(%q<jnunemaker-validatable>, ["= 1.8.0"])
147
147
  s.add_development_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
148
148
  s.add_development_dependency(%q<shoulda>, ["= 2.10.2"])
149
149
  s.add_development_dependency(%q<timecop>, ["= 0.3.1"])
@@ -151,7 +151,7 @@ Gem::Specification.new do |s|
151
151
  else
152
152
  s.add_dependency(%q<activesupport>, [">= 2.3"])
153
153
  s.add_dependency(%q<mongo>, ["= 0.15.1"])
154
- s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.4"])
154
+ s.add_dependency(%q<jnunemaker-validatable>, ["= 1.8.0"])
155
155
  s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
156
156
  s.add_dependency(%q<shoulda>, ["= 2.10.2"])
157
157
  s.add_dependency(%q<timecop>, ["= 0.3.1"])
@@ -160,10 +160,11 @@ Gem::Specification.new do |s|
160
160
  else
161
161
  s.add_dependency(%q<activesupport>, [">= 2.3"])
162
162
  s.add_dependency(%q<mongo>, ["= 0.15.1"])
163
- s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.4"])
163
+ s.add_dependency(%q<jnunemaker-validatable>, ["= 1.8.0"])
164
164
  s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
165
165
  s.add_dependency(%q<shoulda>, ["= 2.10.2"])
166
166
  s.add_dependency(%q<timecop>, ["= 0.3.1"])
167
167
  s.add_dependency(%q<mocha>, ["= 0.9.4"])
168
168
  end
169
169
  end
170
+
data/specs.watchr CHANGED
@@ -4,7 +4,7 @@ def run(cmd)
4
4
  end
5
5
 
6
6
  def run_test_file(file)
7
- run "ruby -Itest #{file}"
7
+ run %Q(ruby -I"lib:test" -rubygems #{file})
8
8
  end
9
9
 
10
10
  def run_all_tests
@@ -12,7 +12,7 @@ def run_all_tests
12
12
  end
13
13
 
14
14
  def related_test_files(path)
15
- Dir['test/**/*.rb'].select { |file| file =~ /#{File.basename(path)}/ }
15
+ Dir['test/**/*.rb'].select { |file| file =~ /test_#{File.basename(path)}/ }
16
16
  end
17
17
 
18
18
  watch('test/test_helper\.rb') { run_all_tests }
@@ -137,7 +137,7 @@ class ManyDocumentsAsProxyTest < Test::Unit::TestCase
137
137
  end
138
138
 
139
139
  should "work with conditions" do
140
- comments = @post.comments.find(:all, :conditions => {:body => 'comment1'})
140
+ comments = @post.comments.find(:all, :body => 'comment1')
141
141
  comments.should == [@comment1]
142
142
  end
143
143
 
@@ -154,7 +154,7 @@ class ManyDocumentsAsProxyTest < Test::Unit::TestCase
154
154
  end
155
155
 
156
156
  should "work with conditions" do
157
- comments = @post.comments.all(:conditions => {:body => 'comment1'})
157
+ comments = @post.comments.all(:body => 'comment1')
158
158
  comments.should == [@comment1]
159
159
  end
160
160
 
@@ -181,7 +181,7 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
181
181
  end
182
182
 
183
183
  should "work with conditions" do
184
- messages = @lounge.messages.find(:all, :conditions => {:body => 'Loungin!'}, :order => "position")
184
+ messages = @lounge.messages.find(:all, :body => 'Loungin!', :order => "position")
185
185
  messages.should == [@lm1]
186
186
  end
187
187
 
@@ -197,7 +197,7 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
197
197
  end
198
198
 
199
199
  should "work with conditions" do
200
- messages = @lounge.messages.all(:conditions => {:body => 'Loungin!'}, :order => "position")
200
+ messages = @lounge.messages.all(:body => 'Loungin!', :order => "position")
201
201
  messages.should == [@lm1]
202
202
  end
203
203
 
@@ -213,7 +213,7 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
213
213
  end
214
214
 
215
215
  should "work with conditions" do
216
- message = @lounge.messages.find(:first, :conditions => {:body => 'I love loungin!'}, :order => "position asc")
216
+ message = @lounge.messages.find(:first, :body => 'I love loungin!', :order => "position asc")
217
217
  message.should == @lm2
218
218
  end
219
219
  end
@@ -224,7 +224,7 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
224
224
  end
225
225
 
226
226
  should "work with conditions" do
227
- message = @lounge.messages.first(:conditions => {:body => 'I love loungin!'}, :order => "position asc")
227
+ message = @lounge.messages.first(:body => 'I love loungin!', :order => "position asc")
228
228
  message.should == @lm2
229
229
  end
230
230
  end
@@ -235,7 +235,7 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
235
235
  end
236
236
 
237
237
  should "work with conditions" do
238
- message = @lounge.messages.find(:last, :conditions => {:body => 'Loungin!'}, :order => "position asc")
238
+ message = @lounge.messages.find(:last, :body => 'Loungin!', :order => "position asc")
239
239
  message.should == @lm1
240
240
  end
241
241
  end
@@ -246,7 +246,7 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
246
246
  end
247
247
 
248
248
  should "work with conditions" do
249
- message = @lounge.messages.last(:conditions => {:body => 'Loungin!'}, :order => "position asc")
249
+ message = @lounge.messages.last(:body => 'Loungin!', :order => "position asc")
250
250
  message.should == @lm1
251
251
  end
252
252
  end
@@ -215,7 +215,7 @@ class ManyProxyTest < Test::Unit::TestCase
215
215
  end
216
216
 
217
217
  should "work with conditions" do
218
- statuses = @project1.statuses.find(:all, :conditions => {'name' => 'Complete'})
218
+ statuses = @project1.statuses.find(:all, :name => 'Complete')
219
219
  statuses.should == [@complete]
220
220
  end
221
221
 
@@ -231,7 +231,7 @@ class ManyProxyTest < Test::Unit::TestCase
231
231
  end
232
232
 
233
233
  should "work with conditions" do
234
- statuses = @project1.statuses.all(:conditions => {'name' => 'Complete'})
234
+ statuses = @project1.statuses.all(:name => 'Complete')
235
235
  statuses.should == [@complete]
236
236
  end
237
237
 
@@ -247,7 +247,7 @@ class ManyProxyTest < Test::Unit::TestCase
247
247
  end
248
248
 
249
249
  should "work with conditions" do
250
- status = @project1.statuses.find(:first, :conditions => {:name => 'Complete'})
250
+ status = @project1.statuses.find(:first, :name => 'Complete')
251
251
  status.should == @complete
252
252
  end
253
253
  end
@@ -258,7 +258,7 @@ class ManyProxyTest < Test::Unit::TestCase
258
258
  end
259
259
 
260
260
  should "work with conditions" do
261
- status = @project1.statuses.first(:conditions => {:name => 'Complete'})
261
+ status = @project1.statuses.first(:name => 'Complete')
262
262
  status.should == @complete
263
263
  end
264
264
  end
@@ -269,7 +269,7 @@ class ManyProxyTest < Test::Unit::TestCase
269
269
  end
270
270
 
271
271
  should "work with conditions" do
272
- status = @project1.statuses.find(:last, :order => 'position', :conditions => {:name => 'New'})
272
+ status = @project1.statuses.find(:last, :order => 'position', :name => 'New')
273
273
  status.should == @brand_new
274
274
  end
275
275
  end
@@ -280,7 +280,7 @@ class ManyProxyTest < Test::Unit::TestCase
280
280
  end
281
281
 
282
282
  should "work with conditions" do
283
- status = @project1.statuses.last(:order => 'position', :conditions => {:name => 'New'})
283
+ status = @project1.statuses.last(:order => 'position', :name => 'New')
284
284
  status.should == @brand_new
285
285
  end
286
286
  end
@@ -24,7 +24,7 @@ class DocumentTest < Test::Unit::TestCase
24
24
  doc.using_custom_id?.should be_false
25
25
  end
26
26
  end
27
-
27
+
28
28
  context "Saving a document with a blank binary value" do
29
29
  setup do
30
30
  @document.key :file, Binary
@@ -41,9 +41,9 @@ class DocumentTest < Test::Unit::TestCase
41
41
  @id = Mongo::ObjectID.new.to_s
42
42
  @document.collection.insert({
43
43
  :_id => @id,
44
- :first_name => 'John',
45
- :last_name => 'Nunemaker',
46
- :age => 27,
44
+ :first_name => 'John',
45
+ :last_name => 'Nunemaker',
46
+ :age => 27,
47
47
  :favorite_color => 'red',
48
48
  :skills => ['ruby', 'rails', 'javascript', 'xhtml', 'css']
49
49
  })
@@ -58,7 +58,7 @@ class DocumentTest < Test::Unit::TestCase
58
58
  doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
59
59
  end
60
60
  end
61
-
61
+
62
62
  context "Document Class Methods" do
63
63
  context "Using key with type Array" do
64
64
  setup do
@@ -141,7 +141,7 @@ class DocumentTest < Test::Unit::TestCase
141
141
  doc.foo['baz'].should == 'bar'
142
142
  end
143
143
  end
144
-
144
+
145
145
  context "Using key with custom type with default" do
146
146
  setup do
147
147
  @document.key :window, WindowSize, :default => WindowSize.new(600, 480)
@@ -150,19 +150,19 @@ class DocumentTest < Test::Unit::TestCase
150
150
  should "default to default" do
151
151
  doc = @document.new
152
152
  doc.window.should == WindowSize.new(600, 480)
153
-
153
+
154
154
  end
155
-
155
+
156
156
  should "save and load from mongo" do
157
157
  doc = @document.new
158
158
  doc.save
159
-
159
+
160
160
  from_db = @document.find(doc.id)
161
161
  from_db.window.should == WindowSize.new(600, 480)
162
162
  end
163
163
  end
164
-
165
-
164
+
165
+
166
166
  context "Creating a single document" do
167
167
  setup do
168
168
  @doc_instance = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
@@ -299,7 +299,9 @@ class DocumentTest < Test::Unit::TestCase
299
299
  end
300
300
 
301
301
  should "raise error if document not found" do
302
- lambda { @document.find(123) }.should raise_error(MongoMapper::DocumentNotFound)
302
+ lambda {
303
+ @document.find(123)
304
+ }.should raise_error(MongoMapper::DocumentNotFound)
303
305
  end
304
306
  end
305
307
 
@@ -311,31 +313,31 @@ class DocumentTest < Test::Unit::TestCase
311
313
  should "work as array" do
312
314
  @document.find([@doc1.id, @doc2.id]).should == [@doc1, @doc2]
313
315
  end
314
-
316
+
315
317
  should "return array if array only has one element" do
316
318
  @document.find([@doc1.id]).should == [@doc1]
317
319
  end
318
320
  end
319
-
321
+
320
322
  should "be able to find using condition auto-detection" do
321
323
  @document.first(:first_name => 'John').should == @doc1
322
324
  @document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
323
325
  end
324
-
326
+
325
327
  context "with :all" do
326
328
  should "find all documents" do
327
329
  @document.find(:all, :order => 'first_name').should == [@doc1, @doc3, @doc2]
328
330
  end
329
331
 
330
332
  should "be able to add conditions" do
331
- @document.find(:all, :conditions => {:first_name => 'John'}).should == [@doc1]
333
+ @document.find(:all, :first_name => 'John').should == [@doc1]
332
334
  end
333
335
  end
334
336
 
335
337
  context "with #all" do
336
338
  should "find all documents based on criteria" do
337
339
  @document.all(:order => 'first_name').should == [@doc1, @doc3, @doc2]
338
- @document.all(:conditions => {:last_name => 'Nunemaker'}, :order => 'age desc').should == [@doc1, @doc3]
340
+ @document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
339
341
  end
340
342
  end
341
343
 
@@ -348,7 +350,7 @@ class DocumentTest < Test::Unit::TestCase
348
350
  context "with #first" do
349
351
  should "find first document based on criteria" do
350
352
  @document.first(:order => 'first_name').should == @doc1
351
- @document.first(:conditions => {:age => 28}).should == @doc2
353
+ @document.first(:age => 28).should == @doc2
352
354
  end
353
355
  end
354
356
 
@@ -361,13 +363,13 @@ class DocumentTest < Test::Unit::TestCase
361
363
  context "with #last" do
362
364
  should "find last document based on criteria" do
363
365
  @document.last(:order => 'age').should == @doc2
364
- @document.last(:order => 'age', :conditions => {:age => 28}).should == @doc2
366
+ @document.last(:order => 'age', :age => 28).should == @doc2
365
367
  end
366
-
368
+
367
369
  should "raise error if no order provided" do
368
370
  lambda { @document.last() }.should raise_error
369
371
  end
370
- end
372
+ end
371
373
 
372
374
  context "with :find_by" do
373
375
  should "find document based on argument" do
@@ -669,11 +671,11 @@ class DocumentTest < Test::Unit::TestCase
669
671
  @thing.properties << @property3
670
672
  end
671
673
 
672
- should_eventually "destroy the thing" do
674
+ should "not execute on a belongs_to association" do
673
675
  Thing.count.should == 1
674
676
  @property1.destroy
675
- Thing.count.should == 0
676
- @property1.thing.should be_frozen
677
+ Thing.count.should == 1
678
+ @property1.should be_frozen
677
679
  end
678
680
  end
679
681
  end
@@ -722,14 +724,14 @@ class DocumentTest < Test::Unit::TestCase
722
724
  should "allow creating index for a key" do
723
725
  @document.ensure_index :first_name
724
726
  MongoMapper.ensure_indexes!
725
-
726
- @document.should have_index('first_name_1')
727
+
728
+ @document.should have_index('first_name_1')
727
729
  end
728
730
 
729
731
  should "allow creating unique index for a key" do
730
732
  @document.ensure_index :first_name, :unique => true
731
733
  MongoMapper.ensure_indexes!
732
-
734
+
733
735
  @document.should have_index('first_name_1')
734
736
  end
735
737
 
@@ -737,13 +739,19 @@ class DocumentTest < Test::Unit::TestCase
737
739
  @document.ensure_index [[:first_name, 1], [:last_name, -1]]
738
740
  MongoMapper.ensure_indexes!
739
741
 
740
- @document.should have_index('last_name_-1_first_name_1')
742
+ # order is different for different versions of ruby so instead of
743
+ # just checking have_index('first_name_1_last_name_-1') I'm checking
744
+ # the values of the indexes to make sure the index creation was successful
745
+ @document.collection.index_information.detect do |index|
746
+ keys = index[1]
747
+ keys.include?(['first_name', 1]) && keys.include?(['last_name', -1])
748
+ end.should_not be_nil
741
749
  end
742
750
 
743
751
  should "work with :index shortcut when defining key" do
744
752
  @document.key :father, String, :index => true
745
753
  MongoMapper.ensure_indexes!
746
-
754
+
747
755
  @document.should have_index('father_1')
748
756
  end
749
757
  end
@@ -794,7 +802,7 @@ class DocumentTest < Test::Unit::TestCase
794
802
  from_db = RealPerson.find(person.id)
795
803
  from_db.name.should == "David"
796
804
  end
797
-
805
+
798
806
  context "with key of type date" do
799
807
  should "save the date value as a Time object" do
800
808
  doc = @document.new(:first_name => 'John', :age => '27', :date => "12/01/2009")
@@ -891,16 +899,16 @@ class DocumentTest < Test::Unit::TestCase
891
899
  from_db.age.should == 30
892
900
  end
893
901
  end
894
-
902
+
895
903
  context "update_attributes" do
896
904
  setup do
897
905
  @document.key :foo, String, :required => true
898
906
  end
899
-
907
+
900
908
  should "return true if document valid" do
901
909
  @document.new.update_attributes(:foo => 'bar').should be_true
902
910
  end
903
-
911
+
904
912
  should "return false if document not valid" do
905
913
  @document.new.update_attributes({}).should be_false
906
914
  end
@@ -941,63 +949,158 @@ class DocumentTest < Test::Unit::TestCase
941
949
  end
942
950
  end
943
951
  end
944
-
952
+
945
953
  context "Single collection inheritance" do
946
954
  setup do
947
955
  class ::DocParent
948
956
  include MongoMapper::Document
949
957
  key :_type, String
958
+ key :name, String
950
959
  end
951
-
952
- class ::DocChild < ::DocParent; end
953
960
  DocParent.collection.clear
954
961
 
962
+ class ::DocDaughter < ::DocParent; end
963
+ class ::DocSon < ::DocParent; end
964
+ class ::DocGrandSon < ::DocSon; end
965
+
955
966
  @parent = DocParent.new({:name => "Daddy Warbucks"})
956
- @child = DocChild.new({:name => "Little Orphan Annie"})
967
+ @daughter = DocDaughter.new({:name => "Little Orphan Annie"})
957
968
  end
958
969
 
959
970
  teardown do
960
- Object.send :remove_const, 'DocParent' if defined?(::DocParent)
961
- Object.send :remove_const, 'DocChild' if defined?(::DocChild)
971
+ Object.send :remove_const, 'DocParent' if defined?(::DocParent)
972
+ Object.send :remove_const, 'DocDaughter' if defined?(::DocDaughter)
973
+ Object.send :remove_const, 'DocSon' if defined?(::DocSon)
974
+ Object.send :remove_const, 'DocGrandSon' if defined?(::DocGrandSon)
962
975
  end
963
976
 
964
977
  should "use the same collection in the subclass" do
965
- DocChild.collection.name.should == DocParent.collection.name
978
+ DocDaughter.collection.name.should == DocParent.collection.name
966
979
  end
967
980
 
968
981
  should "assign the class name into the _type property" do
969
982
  @parent._type.should == 'DocParent'
970
- @child._type.should == 'DocChild'
983
+ @daughter._type.should == 'DocDaughter'
971
984
  end
972
985
 
973
986
  should "load the document with the assigned type" do
974
987
  @parent.save
975
- @child.save
976
-
988
+ @daughter.save
989
+
977
990
  collection = DocParent.find(:all)
978
991
  collection.size.should == 2
979
992
  collection.first.should be_kind_of(DocParent)
980
993
  collection.first.name.should == "Daddy Warbucks"
981
- collection.last.should be_kind_of(DocChild)
994
+ collection.last.should be_kind_of(DocDaughter)
982
995
  collection.last.name.should == "Little Orphan Annie"
983
996
  end
984
-
997
+
985
998
  should "gracefully handle when the type can't be constantized" do
986
999
  doc = DocParent.new(:name => 'Nunes')
987
1000
  doc._type = 'FoobarBaz'
988
1001
  doc.save
989
-
1002
+
990
1003
  collection = DocParent.all
991
1004
  collection.last.should == doc
992
1005
  collection.last.should be_kind_of(DocParent)
993
1006
  end
1007
+
1008
+ should "find scoped to class" do
1009
+ john = DocSon.create(:name => 'John')
1010
+ steve = DocSon.create(:name => 'Steve')
1011
+ steph = DocDaughter.create(:name => 'Steph')
1012
+ carrie = DocDaughter.create(:name => 'Carrie')
1013
+
1014
+ DocGrandSon.all(:order => 'name').should == []
1015
+ DocSon.all(:order => 'name').should == [john, steve]
1016
+ DocDaughter.all(:order => 'name').should == [carrie, steph]
1017
+ DocParent.all(:order => 'name').should == [carrie, john, steph, steve]
1018
+ end
1019
+
1020
+ should "raise error if not found scoped to class" do
1021
+ john = DocSon.create(:name => 'John')
1022
+ steph = DocDaughter.create(:name => 'Steph')
1023
+
1024
+ lambda {
1025
+ DocSon.find(steph.id)
1026
+ }.should raise_error(MongoMapper::DocumentNotFound)
1027
+ end
1028
+
1029
+ should "not raise error for find with parent" do
1030
+ john = DocSon.create(:name => 'John')
1031
+
1032
+ DocParent.find(john.id).should == john
1033
+ end
1034
+
1035
+ should "count scoped to class" do
1036
+ john = DocSon.create(:name => 'John')
1037
+ steve = DocSon.create(:name => 'Steve')
1038
+ steph = DocDaughter.create(:name => 'Steph')
1039
+ carrie = DocDaughter.create(:name => 'Carrie')
1040
+
1041
+ DocGrandSon.count.should == 0
1042
+ DocSon.count.should == 2
1043
+ DocDaughter.count.should == 2
1044
+ DocParent.count.should == 4
1045
+ end
1046
+
1047
+ should "know if it is single_collection_inherited?" do
1048
+ DocParent.single_collection_inherited?.should be_false
1049
+
1050
+ DocDaughter.single_collection_inherited?.should be_true
1051
+ DocSon.single_collection_inherited?.should be_true
1052
+ end
1053
+
1054
+ should "know if single_collection_inherited_superclass?" do
1055
+ DocParent.single_collection_inherited_superclass?.should be_false
1056
+
1057
+ DocDaughter.single_collection_inherited_superclass?.should be_true
1058
+ DocSon.single_collection_inherited_superclass?.should be_true
1059
+ DocGrandSon.single_collection_inherited_superclass?.should be_true
1060
+ end
1061
+
1062
+ should "not be able to destroy each other" do
1063
+ john = DocSon.create(:name => 'John')
1064
+ steph = DocDaughter.create(:name => 'Steph')
1065
+
1066
+ lambda {
1067
+ DocSon.destroy(steph.id)
1068
+ }.should raise_error(MongoMapper::DocumentNotFound)
1069
+ end
1070
+
1071
+ should "not be able to delete each other" do
1072
+ john = DocSon.create(:name => 'John')
1073
+ steph = DocDaughter.create(:name => 'Steph')
1074
+
1075
+ lambda {
1076
+ DocSon.delete(steph.id)
1077
+ }.should_not change { DocParent.count }
1078
+ end
1079
+
1080
+ should "be able to destroy using parent" do
1081
+ john = DocSon.create(:name => 'John')
1082
+ steph = DocDaughter.create(:name => 'Steph')
1083
+
1084
+ lambda {
1085
+ DocParent.destroy_all
1086
+ }.should change { DocParent.count }.by(-2)
1087
+ end
1088
+
1089
+ should "be able to delete using parent" do
1090
+ john = DocSon.create(:name => 'John')
1091
+ steph = DocDaughter.create(:name => 'Steph')
1092
+
1093
+ lambda {
1094
+ DocParent.delete_all
1095
+ }.should change { DocParent.count }.by(-2)
1096
+ end
994
1097
  end
995
1098
 
996
1099
  context "timestamping" do
997
1100
  setup do
998
1101
  @document.timestamps!
999
1102
  end
1000
-
1103
+
1001
1104
  should "set created_at and updated_at on create" do
1002
1105
  doc = @document.new(:first_name => 'John', :age => 27)
1003
1106
  doc.created_at.should be(nil)
@@ -1012,11 +1115,11 @@ class DocumentTest < Test::Unit::TestCase
1012
1115
  old_created_at = doc.created_at
1013
1116
  old_updated_at = doc.updated_at
1014
1117
  doc.first_name = 'Johnny'
1015
-
1118
+
1016
1119
  Timecop.freeze(Time.now + 5.seconds) do
1017
1120
  doc.save
1018
1121
  end
1019
-
1122
+
1020
1123
  doc.created_at.should == old_created_at
1021
1124
  doc.updated_at.should_not == old_updated_at
1022
1125
  end
@@ -1025,7 +1128,7 @@ class DocumentTest < Test::Unit::TestCase
1025
1128
  doc = @document.create(:first_name => 'John', :age => 27)
1026
1129
  old_created_at = doc.created_at
1027
1130
  old_updated_at = doc.updated_at
1028
-
1131
+
1029
1132
  Timecop.freeze(Time.now + 5.seconds) do
1030
1133
  @document.update(doc._id, { :first_name => 'Johnny' })
1031
1134
  end