mongo_mapper 0.5.5 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,89 +1,49 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "mongo_mapper"
8
- gem.summary = %Q{Awesome gem for modeling your domain and storing it in mongo}
9
- gem.email = "nunemaker@gmail.com"
10
- gem.homepage = "http://github.com/jnunemaker/mongomapper"
11
- gem.authors = ["John Nunemaker"]
12
- gem.rubyforge_project = "mongomapper"
13
-
14
- gem.add_dependency('activesupport', '>= 2.3')
15
- gem.add_dependency('mongo', '0.15.1')
16
- gem.add_dependency('jnunemaker-validatable', '1.7.4')
17
-
18
- gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
19
- gem.add_development_dependency('shoulda', '2.10.2')
20
- gem.add_development_dependency('timecop', '0.3.1')
21
- gem.add_development_dependency('mocha', '0.9.4')
22
- end
3
+ require 'jeweler'
4
+ Jeweler::Tasks.new do |gem|
5
+ gem.name = "mongo_mapper"
6
+ gem.summary = %Q{Awesome gem for modeling your domain and storing it in mongo}
7
+ gem.description = %Q{Awesome gem for modeling your domain and storing it in mongo}
8
+ gem.email = "nunemaker@gmail.com"
9
+ gem.homepage = "http://github.com/jnunemaker/mongomapper"
10
+ gem.authors = ["John Nunemaker"]
23
11
 
24
- Jeweler::RubyforgeTasks.new do |rubyforge|
25
- rubyforge.doc_task = "rdoc"
26
- end
27
- rescue LoadError
28
- puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
12
+ gem.add_dependency('activesupport', '>= 2.3')
13
+ gem.add_dependency('mongo', '0.15.1')
14
+ gem.add_dependency('jnunemaker-validatable', '1.8.0')
15
+
16
+ gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
17
+ gem.add_development_dependency('shoulda', '2.10.2')
18
+ gem.add_development_dependency('timecop', '0.3.1')
19
+ gem.add_development_dependency('mocha', '0.9.4')
29
20
  end
30
21
 
22
+ Jeweler::GemcutterTasks.new
23
+
31
24
  require 'rake/testtask'
32
25
  Rake::TestTask.new(:test) do |test|
33
- test.libs << 'lib' << 'test'
26
+ test.libs << 'test'
27
+ test.ruby_opts << '-rubygems'
34
28
  test.pattern = 'test/**/test_*.rb'
35
29
  test.verbose = true
36
30
  end
37
31
 
38
32
  namespace :test do
39
33
  Rake::TestTask.new(:units) do |test|
40
- test.libs << 'lib' << 'test'
34
+ test.libs << 'test'
35
+ test.ruby_opts << '-rubygems'
41
36
  test.pattern = 'test/unit/**/test_*.rb'
42
37
  test.verbose = true
43
38
  end
44
39
 
45
40
  Rake::TestTask.new(:functionals) do |test|
46
- test.libs << 'lib' << 'test'
47
- test.pattern = 'test/functional/**/test_*.rb'
48
- test.verbose = true
49
- end
50
- end
51
-
52
- begin
53
- require 'rcov/rcovtask'
54
- Rcov::RcovTask.new do |test|
55
41
  test.libs << 'test'
56
- test.pattern = 'test/**/test_*.rb'
42
+ test.ruby_opts << '-rubygems'
43
+ test.pattern = 'test/functional/**/test_*.rb'
57
44
  test.verbose = true
58
45
  end
59
- rescue LoadError
60
- task :rcov do
61
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
62
- end
63
- end
64
-
65
- begin
66
- require 'cucumber/rake/task'
67
- Cucumber::Rake::Task.new(:features)
68
- rescue LoadError
69
- task :features do
70
- abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
71
- end
72
46
  end
73
47
 
74
- task :default => :test
75
-
76
- require 'rake/rdoctask'
77
- Rake::RDocTask.new do |rdoc|
78
- if File.exist?('VERSION.yml')
79
- config = YAML.load(File.read('VERSION.yml'))
80
- version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
81
- else
82
- version = ""
83
- end
84
-
85
- rdoc.rdoc_dir = 'rdoc'
86
- rdoc.title = "MongoMapper #{version}"
87
- rdoc.rdoc_files.include('README*')
88
- rdoc.rdoc_files.include('lib/**/*.rb')
89
- end
48
+ task :default => :test
49
+ task :test => :check_dependencies
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.5
1
+ 0.5.6
@@ -1,10 +1,4 @@
1
- require 'rubygems'
2
-
3
- gem 'activesupport', '>= 2.3'
4
- gem 'mongo', '0.15.1'
5
- gem 'jnunemaker-validatable', '1.7.4'
6
-
7
- require 'activesupport'
1
+ require 'active_support'
8
2
  require 'mongo'
9
3
  require 'validatable'
10
4
 
@@ -41,8 +41,6 @@ module MongoMapper
41
41
  if association.options[:dependent]
42
42
  if association.many?
43
43
  define_dependent_callback_for_many(association)
44
- elsif association.belongs_to?
45
- define_dependent_callback_for_belongs_to(association)
46
44
  end
47
45
  end
48
46
  end
@@ -62,14 +60,6 @@ module MongoMapper
62
60
  end
63
61
  end
64
62
 
65
- def define_dependent_callback_for_belongs_to(association)
66
- after_destroy do |doc|
67
- case association.options[:dependent]
68
- when :destroy
69
- doc.get_proxy(association).destroy
70
- end
71
- end
72
- end
73
63
  end
74
64
 
75
65
  module InstanceMethods
@@ -68,7 +68,7 @@ module MongoMapper
68
68
  end
69
69
 
70
70
  def nullify
71
- criteria = FinderOptions.to_mongo_criteria(scoped_conditions)
71
+ criteria = FinderOptions.to_mongo_criteria(klass, scoped_conditions)
72
72
  all(criteria).each do |doc|
73
73
  doc.update_attributes self.foreign_key => nil
74
74
  end
@@ -95,14 +95,14 @@ module MongoMapper
95
95
  end
96
96
 
97
97
  def find_by_id(id)
98
- criteria = FinderOptions.to_mongo_criteria(:_id => id)
98
+ criteria = FinderOptions.to_mongo_criteria(self, :_id => id)
99
99
  if doc = collection.find_one(criteria)
100
100
  new(doc)
101
101
  end
102
102
  end
103
103
 
104
104
  def count(conditions={})
105
- collection.find(FinderOptions.to_mongo_criteria(conditions)).count
105
+ collection.find(FinderOptions.to_mongo_criteria(self, conditions)).count
106
106
  end
107
107
 
108
108
  def exists?(conditions={})
@@ -133,12 +133,12 @@ module MongoMapper
133
133
  end
134
134
 
135
135
  def delete(*ids)
136
- criteria = FinderOptions.to_mongo_criteria(:_id => ids.flatten)
136
+ criteria = FinderOptions.to_mongo_criteria(self, :_id => ids.flatten)
137
137
  collection.remove(criteria)
138
138
  end
139
139
 
140
140
  def delete_all(conditions={})
141
- criteria = FinderOptions.to_mongo_criteria(conditions)
141
+ criteria = FinderOptions.to_mongo_criteria(self, conditions)
142
142
  collection.remove(criteria)
143
143
  end
144
144
 
@@ -147,7 +147,7 @@ module MongoMapper
147
147
  end
148
148
 
149
149
  def destroy_all(conditions={})
150
- find(:all, :conditions => conditions).each(&:destroy)
150
+ all(conditions).each(&:destroy)
151
151
  end
152
152
 
153
153
  def connection(mongo_connection=nil)
@@ -191,6 +191,14 @@ module MongoMapper
191
191
  class_eval { before_save :update_timestamps }
192
192
  end
193
193
 
194
+ def single_collection_inherited?
195
+ keys.has_key?('_type') && single_collection_inherited_superclass?
196
+ end
197
+
198
+ def single_collection_inherited_superclass?
199
+ superclass.respond_to?(:keys) && superclass.keys.has_key?('_type')
200
+ end
201
+
194
202
  protected
195
203
  def method_missing(method, *args)
196
204
  finder = DynamicFinder.new(method)
@@ -221,7 +229,7 @@ module MongoMapper
221
229
  end
222
230
 
223
231
  def find_every(options)
224
- criteria, options = FinderOptions.new(options).to_a
232
+ criteria, options = FinderOptions.new(self, options).to_a
225
233
  collection.find(criteria, options).to_a.map do |doc|
226
234
  begin
227
235
  klass = doc['_type'].present? ? doc['_type'].constantize : self
@@ -304,7 +312,7 @@ module MongoMapper
304
312
  def destroy
305
313
  return false if frozen?
306
314
 
307
- criteria = FinderOptions.to_mongo_criteria(:_id => id)
315
+ criteria = FinderOptions.to_mongo_criteria(self.class, :_id => id)
308
316
  collection.remove(criteria) unless new?
309
317
  freeze
310
318
  end
@@ -1,9 +1,9 @@
1
1
  module MongoMapper
2
- class FinderOptions
3
- attr_reader :options
4
-
5
- def self.to_mongo_criteria(conditions, parent_key=nil)
2
+ class FinderOptions
3
+ def self.to_mongo_criteria(model, conditions, parent_key=nil)
6
4
  criteria = {}
5
+ add_sci_scope(model, criteria)
6
+
7
7
  conditions.each_pair do |field, value|
8
8
  field = field_normalized(field)
9
9
  case value
@@ -15,7 +15,7 @@ module MongoMapper
15
15
  {'$in' => value}
16
16
  end
17
17
  when Hash
18
- criteria[field] = to_mongo_criteria(value, field)
18
+ criteria[field] = to_mongo_criteria(model, value, field)
19
19
  else
20
20
  criteria[field] = value
21
21
  end
@@ -23,8 +23,15 @@ module MongoMapper
23
23
 
24
24
  criteria
25
25
  end
26
+
27
+ # adds _type single collection inheritance scope for models that need it
28
+ def self.add_sci_scope(model, criteria)
29
+ if model.single_collection_inherited?
30
+ criteria[:_type] = model.to_s
31
+ end
32
+ end
26
33
 
27
- def self.to_mongo_options(options)
34
+ def self.to_mongo_options(model, options)
28
35
  options = options.dup
29
36
  {
30
37
  :fields => to_mongo_fields(options.delete(:fields) || options.delete(:select)),
@@ -44,9 +51,13 @@ module MongoMapper
44
51
 
45
52
  OptionKeys = [:fields, :select, :skip, :offset, :limit, :sort, :order]
46
53
 
47
- def initialize(options)
54
+ attr_reader :model, :options
55
+
56
+ def initialize(model, options)
48
57
  raise ArgumentError, "FinderOptions must be a hash" unless options.is_a?(Hash)
49
58
 
59
+ @model = model
60
+
50
61
  options = options.symbolize_keys
51
62
  @options, @conditions = {}, options.delete(:conditions) || {}
52
63
 
@@ -60,11 +71,11 @@ module MongoMapper
60
71
  end
61
72
 
62
73
  def criteria
63
- self.class.to_mongo_criteria(@conditions)
74
+ self.class.to_mongo_criteria(model, @conditions)
64
75
  end
65
76
 
66
77
  def options
67
- self.class.to_mongo_options(@options)
78
+ self.class.to_mongo_options(model, @options)
68
79
  end
69
80
 
70
81
  def to_a
@@ -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
+
@@ -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 }
@@ -23,7 +23,7 @@ class DocumentTest < Test::Unit::TestCase
23
23
  doc.using_custom_id?.should be_false
24
24
  end
25
25
  end
26
-
26
+
27
27
  context "Saving a document with a blank binary value" do
28
28
  setup do
29
29
  @document.key :file, Binary
@@ -40,9 +40,9 @@ class DocumentTest < Test::Unit::TestCase
40
40
  @id = Mongo::ObjectID.new.to_s
41
41
  @document.collection.insert({
42
42
  :_id => @id,
43
- :first_name => 'John',
44
- :last_name => 'Nunemaker',
45
- :age => 27,
43
+ :first_name => 'John',
44
+ :last_name => 'Nunemaker',
45
+ :age => 27,
46
46
  :favorite_color => 'red',
47
47
  :skills => ['ruby', 'rails', 'javascript', 'xhtml', 'css']
48
48
  })
@@ -57,7 +57,7 @@ class DocumentTest < Test::Unit::TestCase
57
57
  doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
58
58
  end
59
59
  end
60
-
60
+
61
61
  context "Document Class Methods" do
62
62
  context "Using key with type Array" do
63
63
  setup do
@@ -140,7 +140,7 @@ class DocumentTest < Test::Unit::TestCase
140
140
  doc.foo['baz'].should == 'bar'
141
141
  end
142
142
  end
143
-
143
+
144
144
  context "Using key with custom type with default" do
145
145
  setup do
146
146
  @document.key :window, WindowSize, :default => WindowSize.new(600, 480)
@@ -149,19 +149,19 @@ class DocumentTest < Test::Unit::TestCase
149
149
  should "default to default" do
150
150
  doc = @document.new
151
151
  doc.window.should == WindowSize.new(600, 480)
152
-
152
+
153
153
  end
154
-
154
+
155
155
  should "save and load from mongo" do
156
156
  doc = @document.new
157
157
  doc.save
158
-
158
+
159
159
  from_db = @document.find(doc.id)
160
160
  from_db.window.should == WindowSize.new(600, 480)
161
161
  end
162
162
  end
163
-
164
-
163
+
164
+
165
165
  context "Creating a single document" do
166
166
  setup do
167
167
  @doc_instance = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
@@ -310,17 +310,17 @@ class DocumentTest < Test::Unit::TestCase
310
310
  should "work as array" do
311
311
  @document.find([@doc1.id, @doc2.id]).should == [@doc1, @doc2]
312
312
  end
313
-
313
+
314
314
  should "return array if array only has one element" do
315
315
  @document.find([@doc1.id]).should == [@doc1]
316
316
  end
317
317
  end
318
-
318
+
319
319
  should "be able to find using condition auto-detection" do
320
320
  @document.first(:first_name => 'John').should == @doc1
321
321
  @document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
322
322
  end
323
-
323
+
324
324
  context "with :all" do
325
325
  should "find all documents" do
326
326
  @document.find(:all, :order => 'first_name').should == [@doc1, @doc3, @doc2]
@@ -362,11 +362,11 @@ class DocumentTest < Test::Unit::TestCase
362
362
  @document.last(:order => 'age').should == @doc2
363
363
  @document.last(:order => 'age', :conditions => {:age => 28}).should == @doc2
364
364
  end
365
-
365
+
366
366
  should "raise error if no order provided" do
367
367
  lambda { @document.last() }.should raise_error
368
368
  end
369
- end
369
+ end
370
370
 
371
371
  context "with :find_by" do
372
372
  should "find document based on argument" do
@@ -668,11 +668,11 @@ class DocumentTest < Test::Unit::TestCase
668
668
  @thing.properties << @property3
669
669
  end
670
670
 
671
- should "destroy the thing" do
671
+ should "not execute on a belongs_to association" do
672
672
  Thing.count.should == 1
673
673
  @property1.destroy
674
- Thing.count.should == 0
675
- @property1.thing.should be_frozen
674
+ Thing.count.should == 1
675
+ @property1.should be_frozen
676
676
  end
677
677
  end
678
678
  end
@@ -721,14 +721,14 @@ class DocumentTest < Test::Unit::TestCase
721
721
  should "allow creating index for a key" do
722
722
  @document.ensure_index :first_name
723
723
  MongoMapper.ensure_indexes!
724
-
725
- @document.should have_index('first_name_1')
724
+
725
+ @document.should have_index('first_name_1')
726
726
  end
727
727
 
728
728
  should "allow creating unique index for a key" do
729
729
  @document.ensure_index :first_name, :unique => true
730
730
  MongoMapper.ensure_indexes!
731
-
731
+
732
732
  @document.should have_index('first_name_1')
733
733
  end
734
734
 
@@ -736,13 +736,19 @@ class DocumentTest < Test::Unit::TestCase
736
736
  @document.ensure_index [[:first_name, 1], [:last_name, -1]]
737
737
  MongoMapper.ensure_indexes!
738
738
 
739
- @document.should have_index('last_name_-1_first_name_1')
739
+ # order is different for different versions of ruby so instead of
740
+ # just checking have_index('first_name_1_last_name_-1') I'm checking
741
+ # the values of the indexes to make sure the index creation was successful
742
+ @document.collection.index_information.detect do |index|
743
+ keys = index[1]
744
+ keys.include?(['first_name', 1]) && keys.include?(['last_name', -1])
745
+ end.should_not be_nil
740
746
  end
741
747
 
742
748
  should "work with :index shortcut when defining key" do
743
749
  @document.key :father, String, :index => true
744
750
  MongoMapper.ensure_indexes!
745
-
751
+
746
752
  @document.should have_index('father_1')
747
753
  end
748
754
  end
@@ -789,7 +795,7 @@ class DocumentTest < Test::Unit::TestCase
789
795
  from_db = RealPerson.find(person.id)
790
796
  from_db.name.should == "David"
791
797
  end
792
-
798
+
793
799
  context "with key of type date" do
794
800
  should "save the date value as a Time object" do
795
801
  doc = @document.new(:first_name => 'John', :age => '27', :date => "12/01/2009")
@@ -886,16 +892,16 @@ class DocumentTest < Test::Unit::TestCase
886
892
  from_db.age.should == 30
887
893
  end
888
894
  end
889
-
895
+
890
896
  context "update_attributes" do
891
897
  setup do
892
898
  @document.key :foo, String, :required => true
893
899
  end
894
-
900
+
895
901
  should "return true if document valid" do
896
902
  @document.new.update_attributes(:foo => 'bar').should be_true
897
903
  end
898
-
904
+
899
905
  should "return false if document not valid" do
900
906
  @document.new.update_attributes({}).should be_false
901
907
  end
@@ -936,63 +942,158 @@ class DocumentTest < Test::Unit::TestCase
936
942
  end
937
943
  end
938
944
  end
939
-
945
+
940
946
  context "Single collection inheritance" do
941
947
  setup do
942
948
  class ::DocParent
943
949
  include MongoMapper::Document
944
950
  key :_type, String
951
+ key :name, String
945
952
  end
946
-
947
- class ::DocChild < ::DocParent; end
948
953
  DocParent.collection.clear
949
954
 
955
+ class ::DocDaughter < ::DocParent; end
956
+ class ::DocSon < ::DocParent; end
957
+ class ::DocGrandSon < ::DocSon; end
958
+
950
959
  @parent = DocParent.new({:name => "Daddy Warbucks"})
951
- @child = DocChild.new({:name => "Little Orphan Annie"})
960
+ @daughter = DocDaughter.new({:name => "Little Orphan Annie"})
952
961
  end
953
962
 
954
963
  teardown do
955
- Object.send :remove_const, 'DocParent' if defined?(::DocParent)
956
- Object.send :remove_const, 'DocChild' if defined?(::DocChild)
964
+ Object.send :remove_const, 'DocParent' if defined?(::DocParent)
965
+ Object.send :remove_const, 'DocDaughter' if defined?(::DocDaughter)
966
+ Object.send :remove_const, 'DocSon' if defined?(::DocSon)
967
+ Object.send :remove_const, 'DocGrandSon' if defined?(::DocGrandSon)
957
968
  end
958
969
 
959
970
  should "use the same collection in the subclass" do
960
- DocChild.collection.name.should == DocParent.collection.name
971
+ DocDaughter.collection.name.should == DocParent.collection.name
961
972
  end
962
973
 
963
974
  should "assign the class name into the _type property" do
964
975
  @parent._type.should == 'DocParent'
965
- @child._type.should == 'DocChild'
976
+ @daughter._type.should == 'DocDaughter'
966
977
  end
967
978
 
968
979
  should "load the document with the assigned type" do
969
980
  @parent.save
970
- @child.save
971
-
981
+ @daughter.save
982
+
972
983
  collection = DocParent.find(:all)
973
984
  collection.size.should == 2
974
985
  collection.first.should be_kind_of(DocParent)
975
986
  collection.first.name.should == "Daddy Warbucks"
976
- collection.last.should be_kind_of(DocChild)
987
+ collection.last.should be_kind_of(DocDaughter)
977
988
  collection.last.name.should == "Little Orphan Annie"
978
989
  end
979
-
990
+
980
991
  should "gracefully handle when the type can't be constantized" do
981
992
  doc = DocParent.new(:name => 'Nunes')
982
993
  doc._type = 'FoobarBaz'
983
994
  doc.save
984
-
995
+
985
996
  collection = DocParent.all
986
997
  collection.last.should == doc
987
998
  collection.last.should be_kind_of(DocParent)
988
999
  end
1000
+
1001
+ should "find scoped to class" do
1002
+ john = DocSon.create(:name => 'John')
1003
+ steve = DocSon.create(:name => 'Steve')
1004
+ steph = DocDaughter.create(:name => 'Steph')
1005
+ carrie = DocDaughter.create(:name => 'Carrie')
1006
+
1007
+ DocGrandSon.all(:order => 'name').should == []
1008
+ DocSon.all(:order => 'name').should == [john, steve]
1009
+ DocDaughter.all(:order => 'name').should == [carrie, steph]
1010
+ DocParent.all(:order => 'name').should == [carrie, john, steph, steve]
1011
+ end
1012
+
1013
+ should "raise error if not found scoped to class" do
1014
+ john = DocSon.create(:name => 'John')
1015
+ steph = DocDaughter.create(:name => 'Steph')
1016
+
1017
+ lambda {
1018
+ DocSon.find(steph.id)
1019
+ }.should raise_error(MongoMapper::DocumentNotFound)
1020
+ end
1021
+
1022
+ should "not raise error for find with parent" do
1023
+ john = DocSon.create(:name => 'John')
1024
+
1025
+ DocParent.find(john.id).should == john
1026
+ end
1027
+
1028
+ should "count scoped to class" do
1029
+ john = DocSon.create(:name => 'John')
1030
+ steve = DocSon.create(:name => 'Steve')
1031
+ steph = DocDaughter.create(:name => 'Steph')
1032
+ carrie = DocDaughter.create(:name => 'Carrie')
1033
+
1034
+ DocGrandSon.count.should == 0
1035
+ DocSon.count.should == 2
1036
+ DocDaughter.count.should == 2
1037
+ DocParent.count.should == 4
1038
+ end
1039
+
1040
+ should "know if it is single_collection_inherited?" do
1041
+ DocParent.single_collection_inherited?.should be_false
1042
+
1043
+ DocDaughter.single_collection_inherited?.should be_true
1044
+ DocSon.single_collection_inherited?.should be_true
1045
+ end
1046
+
1047
+ should "know if single_collection_inherited_superclass?" do
1048
+ DocParent.single_collection_inherited_superclass?.should be_false
1049
+
1050
+ DocDaughter.single_collection_inherited_superclass?.should be_true
1051
+ DocSon.single_collection_inherited_superclass?.should be_true
1052
+ DocGrandSon.single_collection_inherited_superclass?.should be_true
1053
+ end
1054
+
1055
+ should "not be able to destroy each other" do
1056
+ john = DocSon.create(:name => 'John')
1057
+ steph = DocDaughter.create(:name => 'Steph')
1058
+
1059
+ lambda {
1060
+ DocSon.destroy(steph.id)
1061
+ }.should raise_error(MongoMapper::DocumentNotFound)
1062
+ end
1063
+
1064
+ should "not be able to delete each other" do
1065
+ john = DocSon.create(:name => 'John')
1066
+ steph = DocDaughter.create(:name => 'Steph')
1067
+
1068
+ lambda {
1069
+ DocSon.delete(steph.id)
1070
+ }.should_not change { DocParent.count }
1071
+ end
1072
+
1073
+ should "be able to destroy using parent" do
1074
+ john = DocSon.create(:name => 'John')
1075
+ steph = DocDaughter.create(:name => 'Steph')
1076
+
1077
+ lambda {
1078
+ DocParent.destroy_all
1079
+ }.should change { DocParent.count }.by(-2)
1080
+ end
1081
+
1082
+ should "be able to delete using parent" do
1083
+ john = DocSon.create(:name => 'John')
1084
+ steph = DocDaughter.create(:name => 'Steph')
1085
+
1086
+ lambda {
1087
+ DocParent.delete_all
1088
+ }.should change { DocParent.count }.by(-2)
1089
+ end
989
1090
  end
990
1091
 
991
1092
  context "timestamping" do
992
1093
  setup do
993
1094
  @document.timestamps!
994
1095
  end
995
-
1096
+
996
1097
  should "set created_at and updated_at on create" do
997
1098
  doc = @document.new(:first_name => 'John', :age => 27)
998
1099
  doc.created_at.should be(nil)
@@ -1007,11 +1108,11 @@ class DocumentTest < Test::Unit::TestCase
1007
1108
  old_created_at = doc.created_at
1008
1109
  old_updated_at = doc.updated_at
1009
1110
  doc.first_name = 'Johnny'
1010
-
1111
+
1011
1112
  Timecop.freeze(Time.now + 5.seconds) do
1012
1113
  doc.save
1013
1114
  end
1014
-
1115
+
1015
1116
  doc.created_at.should == old_created_at
1016
1117
  doc.updated_at.should_not == old_updated_at
1017
1118
  end
@@ -1020,7 +1121,7 @@ class DocumentTest < Test::Unit::TestCase
1020
1121
  doc = @document.create(:first_name => 'John', :age => 27)
1021
1122
  old_created_at = doc.created_at
1022
1123
  old_updated_at = doc.updated_at
1023
-
1124
+
1024
1125
  Timecop.freeze(Time.now + 5.seconds) do
1025
1126
  @document.update(doc._id, { :first_name => 'Johnny' })
1026
1127
  end
@@ -68,12 +68,6 @@ class Message
68
68
  belongs_to :room
69
69
  end
70
70
 
71
- class Answer
72
- include MongoMapper::Document
73
-
74
- key :body, String
75
- end
76
-
77
71
  class Enter < Message; end
78
72
  class Exit < Message; end
79
73
  class Chat < Message; end
@@ -85,6 +79,12 @@ class Room
85
79
  many :messages, :polymorphic => true
86
80
  end
87
81
 
82
+ class Answer
83
+ include MongoMapper::Document
84
+
85
+ key :body, String
86
+ end
87
+
88
88
  class Project
89
89
  include MongoMapper::Document
90
90
 
@@ -1,73 +1,87 @@
1
1
  require 'test_helper'
2
+ require 'models'
2
3
 
3
4
  class FinderOptionsTest < Test::Unit::TestCase
4
5
  include MongoMapper
5
6
 
6
7
  should "raise error if provided something other than a hash" do
7
- lambda { FinderOptions.new }.should raise_error(ArgumentError)
8
- lambda { FinderOptions.new(1) }.should raise_error(ArgumentError)
8
+ lambda { FinderOptions.new(Room) }.should raise_error(ArgumentError)
9
+ lambda { FinderOptions.new(Room, 1) }.should raise_error(ArgumentError)
9
10
  end
10
11
 
11
12
  should "symbolize the keys of the hash provided" do
12
- FinderOptions.new('offset' => 1).options.keys.map do |key|
13
+ FinderOptions.new(Room, 'offset' => 1).options.keys.map do |key|
13
14
  key.should be_instance_of(Symbol)
14
15
  end
15
16
  end
16
17
 
17
18
  context "#criteria" do
18
19
  should "convert conditions to criteria" do
19
- FinderOptions.expects(:to_mongo_criteria).with(:foo => 1).returns({})
20
- FinderOptions.new(:conditions => {:foo => 1}).criteria
20
+ FinderOptions.expects(:to_mongo_criteria).with(Room, :foo => 1).returns({})
21
+ FinderOptions.new(Room, :conditions => {:foo => 1}).criteria
21
22
  end
22
23
  end
23
24
 
24
25
  context "#options" do
25
26
  should "convert options to mongo options" do
26
- FinderOptions.expects(:to_mongo_options).with(:order => 'foo asc', :select => 'foo,bar').returns({})
27
- FinderOptions.new(:order => 'foo asc', :select => 'foo,bar').options
27
+ FinderOptions.expects(:to_mongo_options).with(Room, :order => 'foo asc', :select => 'foo,bar').returns({})
28
+ FinderOptions.new(Room, :order => 'foo asc', :select => 'foo,bar').options
28
29
  end
29
30
  end
30
31
 
31
32
  context "Converting conditions to criteria" do
33
+ should "not add _type to query if model does not have superclass that is single collection inherited" do
34
+ FinderOptions.to_mongo_criteria(Message, :foo => 'bar').should == {
35
+ :foo => 'bar'
36
+ }
37
+ end
38
+
39
+ should "automatically add _type to query if model is single collection inherited" do
40
+ FinderOptions.to_mongo_criteria(Enter, :foo => 'bar').should == {
41
+ :foo => 'bar',
42
+ :_type => 'Enter'
43
+ }
44
+ end
45
+
32
46
  should "work with simple criteria" do
33
- FinderOptions.to_mongo_criteria(:foo => 'bar').should == {
47
+ FinderOptions.to_mongo_criteria(Room, :foo => 'bar').should == {
34
48
  :foo => 'bar'
35
49
  }
36
50
 
37
- FinderOptions.to_mongo_criteria(:foo => 'bar', :baz => 'wick').should == {
51
+ FinderOptions.to_mongo_criteria(Room, :foo => 'bar', :baz => 'wick').should == {
38
52
  :foo => 'bar',
39
53
  :baz => 'wick'
40
54
  }
41
55
  end
42
56
 
43
57
  should "convert id to _id" do
44
- FinderOptions.to_mongo_criteria(:id => '1').should == {
58
+ FinderOptions.to_mongo_criteria(Room, :id => '1').should == {
45
59
  :_id => '1'
46
60
  }
47
61
  end
48
62
 
49
63
  should "use $in for arrays" do
50
- FinderOptions.to_mongo_criteria(:foo => [1,2,3]).should == {
64
+ FinderOptions.to_mongo_criteria(Room, :foo => [1,2,3]).should == {
51
65
  :foo => {'$in' => [1,2,3]}
52
66
  }
53
67
  end
54
68
 
55
69
  should "not use $in for arrays if already using array operator" do
56
- FinderOptions.to_mongo_criteria(:foo => {'$all' => [1,2,3]}).should == {
70
+ FinderOptions.to_mongo_criteria(Room, :foo => {'$all' => [1,2,3]}).should == {
57
71
  :foo => {'$all' => [1,2,3]}
58
72
  }
59
73
 
60
- FinderOptions.to_mongo_criteria(:foo => {'$any' => [1,2,3]}).should == {
74
+ FinderOptions.to_mongo_criteria(Room, :foo => {'$any' => [1,2,3]}).should == {
61
75
  :foo => {'$any' => [1,2,3]}
62
76
  }
63
77
  end
64
78
 
65
79
  should "work arbitrarily deep" do
66
- FinderOptions.to_mongo_criteria(:foo => {:bar => [1,2,3]}).should == {
80
+ FinderOptions.to_mongo_criteria(Room, :foo => {:bar => [1,2,3]}).should == {
67
81
  :foo => {:bar => {'$in' => [1,2,3]}}
68
82
  }
69
83
 
70
- FinderOptions.to_mongo_criteria(:foo => {:bar => {'$any' => [1,2,3]}}).should == {
84
+ FinderOptions.to_mongo_criteria(Room, :foo => {:bar => {'$any' => [1,2,3]}}).should == {
71
85
  :foo => {:bar => {'$any' => [1,2,3]}}
72
86
  }
73
87
  end
@@ -76,166 +90,166 @@ class FinderOptionsTest < Test::Unit::TestCase
76
90
  context "ordering" do
77
91
  should "single field with ascending direction" do
78
92
  sort = [['foo', 1]]
79
- FinderOptions.to_mongo_options(:order => 'foo asc')[:sort].should == sort
80
- FinderOptions.to_mongo_options(:order => 'foo ASC')[:sort].should == sort
93
+ FinderOptions.to_mongo_options(Room, :order => 'foo asc')[:sort].should == sort
94
+ FinderOptions.to_mongo_options(Room, :order => 'foo ASC')[:sort].should == sort
81
95
  end
82
96
 
83
97
  should "single field with descending direction" do
84
98
  sort = [['foo', -1]]
85
- FinderOptions.to_mongo_options(:order => 'foo desc')[:sort].should == sort
86
- FinderOptions.to_mongo_options(:order => 'foo DESC')[:sort].should == sort
99
+ FinderOptions.to_mongo_options(Room, :order => 'foo desc')[:sort].should == sort
100
+ FinderOptions.to_mongo_options(Room, :order => 'foo DESC')[:sort].should == sort
87
101
  end
88
102
 
89
103
  should "convert field without direction to ascending" do
90
104
  sort = [['foo', 1]]
91
- FinderOptions.to_mongo_options(:order => 'foo')[:sort].should == sort
105
+ FinderOptions.to_mongo_options(Room, :order => 'foo')[:sort].should == sort
92
106
  end
93
107
 
94
108
  should "convert multiple fields with directions" do
95
109
  sort = [['foo', -1], ['bar', 1], ['baz', -1]]
96
- FinderOptions.to_mongo_options(:order => 'foo desc, bar asc, baz desc')[:sort].should == sort
110
+ FinderOptions.to_mongo_options(Room, :order => 'foo desc, bar asc, baz desc')[:sort].should == sort
97
111
  end
98
112
 
99
113
  should "convert multiple fields with some missing directions" do
100
114
  sort = [['foo', -1], ['bar', 1], ['baz', 1]]
101
- FinderOptions.to_mongo_options(:order => 'foo desc, bar, baz')[:sort].should == sort
115
+ FinderOptions.to_mongo_options(Room, :order => 'foo desc, bar, baz')[:sort].should == sort
102
116
  end
103
117
 
104
118
  should "just use sort if sort and order are present" do
105
119
  sort = [['$natural', 1]]
106
- FinderOptions.to_mongo_options(:sort => sort, :order => 'foo asc')[:sort].should == sort
120
+ FinderOptions.to_mongo_options(Room, :sort => sort, :order => 'foo asc')[:sort].should == sort
107
121
  end
108
122
 
109
123
  should "convert natural in order to proper" do
110
124
  sort = [['$natural', 1]]
111
- FinderOptions.to_mongo_options(:order => '$natural asc')[:sort].should == sort
125
+ FinderOptions.to_mongo_options(Room, :order => '$natural asc')[:sort].should == sort
112
126
  sort = [['$natural', -1]]
113
- FinderOptions.to_mongo_options(:order => '$natural desc')[:sort].should == sort
127
+ FinderOptions.to_mongo_options(Room, :order => '$natural desc')[:sort].should == sort
114
128
  end
115
129
 
116
130
  should "work for natural order ascending" do
117
- FinderOptions.to_mongo_options(:sort => {'$natural' => 1})[:sort]['$natural'].should == 1
131
+ FinderOptions.to_mongo_options(Room, :sort => {'$natural' => 1})[:sort]['$natural'].should == 1
118
132
  end
119
133
 
120
134
  should "work for natural order descending" do
121
- FinderOptions.to_mongo_options(:sort => {'$natural' => -1})[:sort]['$natural'].should == -1
135
+ FinderOptions.to_mongo_options(Room, :sort => {'$natural' => -1})[:sort]['$natural'].should == -1
122
136
  end
123
137
  end
124
138
 
125
139
  context "skip" do
126
140
  should "default to 0" do
127
- FinderOptions.to_mongo_options({})[:skip].should == 0
141
+ FinderOptions.to_mongo_options(Room, {})[:skip].should == 0
128
142
  end
129
143
 
130
144
  should "use skip provided" do
131
- FinderOptions.to_mongo_options(:skip => 2)[:skip].should == 2
145
+ FinderOptions.to_mongo_options(Room, :skip => 2)[:skip].should == 2
132
146
  end
133
147
 
134
148
  should "covert string to integer" do
135
- FinderOptions.to_mongo_options(:skip => '2')[:skip].should == 2
149
+ FinderOptions.to_mongo_options(Room, :skip => '2')[:skip].should == 2
136
150
  end
137
151
 
138
152
  should "convert offset to skip" do
139
- FinderOptions.to_mongo_options(:offset => 1)[:skip].should == 1
153
+ FinderOptions.to_mongo_options(Room, :offset => 1)[:skip].should == 1
140
154
  end
141
155
  end
142
156
 
143
157
  context "limit" do
144
158
  should "default to 0" do
145
- FinderOptions.to_mongo_options({})[:limit].should == 0
159
+ FinderOptions.to_mongo_options(Room, {})[:limit].should == 0
146
160
  end
147
161
 
148
162
  should "use limit provided" do
149
- FinderOptions.to_mongo_options(:limit => 2)[:limit].should == 2
163
+ FinderOptions.to_mongo_options(Room, :limit => 2)[:limit].should == 2
150
164
  end
151
165
 
152
166
  should "covert string to integer" do
153
- FinderOptions.to_mongo_options(:limit => '2')[:limit].should == 2
167
+ FinderOptions.to_mongo_options(Room, :limit => '2')[:limit].should == 2
154
168
  end
155
169
  end
156
170
 
157
171
  context "fields" do
158
172
  should "default to nil" do
159
- FinderOptions.to_mongo_options({})[:fields].should be(nil)
173
+ FinderOptions.to_mongo_options(Room, {})[:fields].should be(nil)
160
174
  end
161
175
 
162
176
  should "be converted to nil if empty string" do
163
- FinderOptions.to_mongo_options(:fields => '')[:fields].should be(nil)
177
+ FinderOptions.to_mongo_options(Room, :fields => '')[:fields].should be(nil)
164
178
  end
165
179
 
166
180
  should "be converted to nil if []" do
167
- FinderOptions.to_mongo_options(:fields => [])[:fields].should be(nil)
181
+ FinderOptions.to_mongo_options(Room, :fields => [])[:fields].should be(nil)
168
182
  end
169
183
 
170
184
  should "should work with array" do
171
- FinderOptions.to_mongo_options({:fields => %w(a b)})[:fields].should == %w(a b)
185
+ FinderOptions.to_mongo_options(Room, {:fields => %w(a b)})[:fields].should == %w(a b)
172
186
  end
173
187
 
174
188
  should "convert comma separated list to array" do
175
- FinderOptions.to_mongo_options({:fields => 'a, b'})[:fields].should == %w(a b)
189
+ FinderOptions.to_mongo_options(Room, {:fields => 'a, b'})[:fields].should == %w(a b)
176
190
  end
177
191
 
178
192
  should "also work as select" do
179
- FinderOptions.new(:select => %w(a b)).options[:fields].should == %w(a b)
193
+ FinderOptions.new(Room, :select => %w(a b)).options[:fields].should == %w(a b)
180
194
  end
181
195
  end
182
196
 
183
197
  context "Condition auto-detection" do
184
198
  should "know :conditions are criteria" do
185
- finder = FinderOptions.new(:conditions => {:foo => 'bar'})
199
+ finder = FinderOptions.new(Room, :conditions => {:foo => 'bar'})
186
200
  finder.criteria.should == {:foo => 'bar'}
187
201
  finder.options.keys.should_not include(:conditions)
188
202
  end
189
203
 
190
204
  should "know fields is an option" do
191
- finder = FinderOptions.new(:fields => ['foo'])
205
+ finder = FinderOptions.new(Room, :fields => ['foo'])
192
206
  finder.options[:fields].should == ['foo']
193
207
  finder.criteria.keys.should_not include(:fields)
194
208
  end
195
209
 
196
210
  # select gets converted to fields so just checking keys
197
211
  should "know select is an option" do
198
- finder = FinderOptions.new(:select => 'foo')
212
+ finder = FinderOptions.new(Room, :select => 'foo')
199
213
  finder.options.keys.should include(:sort)
200
214
  finder.criteria.keys.should_not include(:select)
201
215
  finder.criteria.keys.should_not include(:fields)
202
216
  end
203
217
 
204
218
  should "know skip is an option" do
205
- finder = FinderOptions.new(:skip => 10)
219
+ finder = FinderOptions.new(Room, :skip => 10)
206
220
  finder.options[:skip].should == 10
207
221
  finder.criteria.keys.should_not include(:skip)
208
222
  end
209
223
 
210
224
  # offset gets converted to skip so just checking keys
211
225
  should "know offset is an option" do
212
- finder = FinderOptions.new(:offset => 10)
226
+ finder = FinderOptions.new(Room, :offset => 10)
213
227
  finder.options.keys.should include(:skip)
214
228
  finder.criteria.keys.should_not include(:skip)
215
229
  finder.criteria.keys.should_not include(:offset)
216
230
  end
217
231
 
218
232
  should "know limit is an option" do
219
- finder = FinderOptions.new(:limit => 10)
233
+ finder = FinderOptions.new(Room, :limit => 10)
220
234
  finder.options[:limit].should == 10
221
235
  finder.criteria.keys.should_not include(:limit)
222
236
  end
223
237
 
224
238
  should "know sort is an option" do
225
- finder = FinderOptions.new(:sort => [['foo', 1]])
239
+ finder = FinderOptions.new(Room, :sort => [['foo', 1]])
226
240
  finder.options[:sort].should == [['foo', 1]]
227
241
  finder.criteria.keys.should_not include(:sort)
228
242
  end
229
243
 
230
244
  # order gets converted to sort so just checking keys
231
245
  should "know order is an option" do
232
- finder = FinderOptions.new(:order => 'foo')
246
+ finder = FinderOptions.new(Room, :order => 'foo')
233
247
  finder.options.keys.should include(:sort)
234
248
  finder.criteria.keys.should_not include(:sort)
235
249
  end
236
250
 
237
251
  should "work with full range of things" do
238
- finder_options = FinderOptions.new({
252
+ finder_options = FinderOptions.new(Room, {
239
253
  :foo => 'bar',
240
254
  :baz => true,
241
255
  :sort => [['foo', 1]],
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongo_mapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.5
4
+ version: 0.5.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-16 00:00:00 -04:00
12
+ date: 2009-10-22 00:00:00 -04:00
13
13
  default_executable: mmconsole
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -40,7 +40,7 @@ dependencies:
40
40
  requirements:
41
41
  - - "="
42
42
  - !ruby/object:Gem::Version
43
- version: 1.7.4
43
+ version: 1.8.0
44
44
  version:
45
45
  - !ruby/object:Gem::Dependency
46
46
  name: jnunemaker-matchy
@@ -82,7 +82,7 @@ dependencies:
82
82
  - !ruby/object:Gem::Version
83
83
  version: 0.9.4
84
84
  version:
85
- description:
85
+ description: Awesome gem for modeling your domain and storing it in mongo
86
86
  email: nunemaker@gmail.com
87
87
  executables:
88
88
  - mmconsole
@@ -187,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
187
187
  version:
188
188
  requirements: []
189
189
 
190
- rubyforge_project: mongomapper
190
+ rubyforge_project:
191
191
  rubygems_version: 1.3.5
192
192
  signing_key:
193
193
  specification_version: 3