mongo_mapper 0.5.5 → 0.5.6

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.
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