mongo_mapper 0.5.2 → 0.5.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +18 -7
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/mongo_mapper.rb +16 -1
- data/lib/mongo_mapper/associations/proxy.rb +11 -1
- data/lib/mongo_mapper/document.rb +33 -2
- data/lib/mongo_mapper/embedded_document.rb +20 -25
- data/lib/mongo_mapper/finder_options.rb +13 -2
- data/lib/mongo_mapper/support.rb +5 -1
- data/mongo_mapper.gemspec +5 -5
- data/test/custom_matchers.rb +7 -0
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +7 -6
- data/test/functional/associations/test_belongs_to_proxy.rb +7 -4
- data/test/functional/test_document.rb +115 -23
- data/test/functional/test_embedded_document.rb +1 -1
- data/test/models.rb +26 -0
- data/test/unit/test_document.rb +20 -1
- data/test/unit/test_embedded_document.rb +11 -0
- data/test/unit/test_finder_options.rb +80 -1
- data/test/unit/test_support.rb +21 -2
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -2,11 +2,7 @@
|
|
2
2
|
|
3
3
|
Awesome gem for modeling your domain and storing it in mongo.
|
4
4
|
|
5
|
-
Releases are tagged on github and
|
6
|
-
|
7
|
-
* rake gemspec
|
8
|
-
* gem build mongo_mapper.gemspec
|
9
|
-
* gem install the gem that was built
|
5
|
+
Releases are tagged on github and released on gemcutter. Master is pushed to whenever I add a patch or a new feature, but I do not release a new gem version each time I push.
|
10
6
|
|
11
7
|
== Note on Patches/Pull Requests
|
12
8
|
|
@@ -16,10 +12,25 @@ Releases are tagged on github and also released as gems on github and rubyforge.
|
|
16
12
|
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull)
|
17
13
|
* Send me a pull request. Bonus points for topic branches.
|
18
14
|
|
15
|
+
== Install
|
16
|
+
|
17
|
+
MongoMapper is only released on gemcutter. To install, you can setup gemcutter as your default gem source.
|
18
|
+
|
19
|
+
$ gem install gemcutter
|
20
|
+
$ gem tumble
|
21
|
+
|
22
|
+
Then you can install MM:
|
23
|
+
|
24
|
+
$ gem install mongo_mapper
|
25
|
+
|
26
|
+
You can also just declare the source:
|
27
|
+
|
28
|
+
$ gem install mongo_mapper -s http://gemcutter.org
|
29
|
+
|
19
30
|
== Dependencies
|
20
31
|
|
21
|
-
* ActiveSupport (
|
22
|
-
* Mongo Ruby Driver (
|
32
|
+
* ActiveSupport (typically the latest version)
|
33
|
+
* Mongo Ruby Driver (mongo)
|
23
34
|
* My fork of the validatable gem (jnunemaker-validatable)
|
24
35
|
|
25
36
|
== Documentation
|
data/Rakefile
CHANGED
@@ -13,7 +13,7 @@ begin
|
|
13
13
|
|
14
14
|
gem.add_dependency('activesupport')
|
15
15
|
gem.add_dependency('mongo', '0.15.1')
|
16
|
-
gem.add_dependency('jnunemaker-validatable', '1.7.
|
16
|
+
gem.add_dependency('jnunemaker-validatable', '1.7.4')
|
17
17
|
|
18
18
|
gem.add_development_dependency('mocha', '0.9.4')
|
19
19
|
gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.3
|
data/lib/mongo_mapper.rb
CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
|
|
2
2
|
|
3
3
|
gem 'activesupport'
|
4
4
|
gem 'mongo', '0.15.1'
|
5
|
-
gem 'jnunemaker-validatable', '1.7.
|
5
|
+
gem 'jnunemaker-validatable', '1.7.4'
|
6
6
|
|
7
7
|
require 'activesupport'
|
8
8
|
require 'mongo'
|
@@ -42,6 +42,21 @@ module MongoMapper
|
|
42
42
|
@@database ||= MongoMapper.connection.db(@@database_name)
|
43
43
|
end
|
44
44
|
|
45
|
+
def self.ensured_indexes
|
46
|
+
@@ensured_indexes ||= []
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.ensure_index(klass, keys, options={})
|
50
|
+
ensured_indexes << {:klass => klass, :keys => keys, :options => options}
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.ensure_indexes!
|
54
|
+
ensured_indexes.each do |index|
|
55
|
+
unique = index[:options].delete(:unique)
|
56
|
+
index[:klass].collection.create_index(index[:keys], unique)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
45
60
|
module Finders
|
46
61
|
def dynamic_find(finder, args)
|
47
62
|
attributes = {}
|
@@ -32,7 +32,17 @@ module MongoMapper
|
|
32
32
|
def replace(v)
|
33
33
|
raise NotImplementedError
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
|
+
def inspect
|
37
|
+
load_target
|
38
|
+
@target.inspect
|
39
|
+
end
|
40
|
+
|
41
|
+
def nil?
|
42
|
+
load_target
|
43
|
+
@target.nil?
|
44
|
+
end
|
45
|
+
|
36
46
|
protected
|
37
47
|
def method_missing(method, *args)
|
38
48
|
if load_target
|
@@ -28,6 +28,22 @@ module MongoMapper
|
|
28
28
|
end
|
29
29
|
|
30
30
|
module ClassMethods
|
31
|
+
def key(*args)
|
32
|
+
key = super
|
33
|
+
create_indexes_for(key)
|
34
|
+
key
|
35
|
+
end
|
36
|
+
|
37
|
+
def ensure_index(name_or_array, options={})
|
38
|
+
keys_to_index = if name_or_array.is_a?(Array)
|
39
|
+
name_or_array.map { |pair| [pair[0], pair[1]] }
|
40
|
+
else
|
41
|
+
name_or_array
|
42
|
+
end
|
43
|
+
|
44
|
+
MongoMapper.ensure_index(self, keys_to_index, options)
|
45
|
+
end
|
46
|
+
|
31
47
|
def find(*args)
|
32
48
|
options = args.extract_options!
|
33
49
|
case args.first
|
@@ -90,6 +106,10 @@ module MongoMapper
|
|
90
106
|
collection.find(FinderOptions.to_mongo_criteria(conditions)).count
|
91
107
|
end
|
92
108
|
|
109
|
+
def exists?(conditions={})
|
110
|
+
!count(conditions).zero?
|
111
|
+
end
|
112
|
+
|
93
113
|
def create(*docs)
|
94
114
|
instances = []
|
95
115
|
docs = [{}] if docs.blank?
|
@@ -187,9 +207,20 @@ module MongoMapper
|
|
187
207
|
end
|
188
208
|
|
189
209
|
private
|
210
|
+
def create_indexes_for(key)
|
211
|
+
ensure_index key.name if key.options[:index]
|
212
|
+
end
|
213
|
+
|
190
214
|
def find_every(options)
|
191
215
|
criteria, options = FinderOptions.new(options).to_a
|
192
|
-
collection.find(criteria, options).to_a.map
|
216
|
+
collection.find(criteria, options).to_a.map do |doc|
|
217
|
+
begin
|
218
|
+
klass = doc['_type'].present? ? doc['_type'].constantize : self
|
219
|
+
klass.new(doc)
|
220
|
+
rescue NameError
|
221
|
+
new(doc)
|
222
|
+
end
|
223
|
+
end
|
193
224
|
end
|
194
225
|
|
195
226
|
def invert_order_clause(order)
|
@@ -244,7 +275,7 @@ module MongoMapper
|
|
244
275
|
end
|
245
276
|
end
|
246
277
|
|
247
|
-
module InstanceMethods
|
278
|
+
module InstanceMethods
|
248
279
|
def collection
|
249
280
|
self.class.collection
|
250
281
|
end
|
@@ -22,6 +22,10 @@ module MongoMapper
|
|
22
22
|
end
|
23
23
|
|
24
24
|
module ClassMethods
|
25
|
+
def logger
|
26
|
+
MongoMapper.logger
|
27
|
+
end
|
28
|
+
|
25
29
|
def inherited(subclass)
|
26
30
|
unless subclass.embeddable?
|
27
31
|
subclass.set_collection_name(collection_name)
|
@@ -49,30 +53,13 @@ module MongoMapper
|
|
49
53
|
keys[key.name] = key
|
50
54
|
|
51
55
|
create_accessors_for(key)
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
+
create_key_in_subclasses(*args)
|
57
|
+
create_validations_for(key)
|
58
|
+
|
56
59
|
key
|
57
60
|
end
|
58
|
-
|
59
|
-
|
60
|
-
def add_to_subclasses(*args)
|
61
|
-
return if subclasses.blank?
|
62
|
-
|
63
|
-
subclasses.each do |subclass|
|
64
|
-
subclass.key(*args)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def ensure_index(name_or_array, options={})
|
69
|
-
keys_to_index = if name_or_array.is_a?(Array)
|
70
|
-
name_or_array.map { |pair| [pair[0], pair[1]] }
|
71
|
-
else
|
72
|
-
name_or_array
|
73
|
-
end
|
74
|
-
|
75
|
-
collection.create_index(keys_to_index, options.delete(:unique))
|
61
|
+
|
62
|
+
key
|
76
63
|
end
|
77
64
|
|
78
65
|
def embeddable?
|
@@ -129,12 +116,16 @@ module MongoMapper
|
|
129
116
|
end_eval
|
130
117
|
include accessors_module
|
131
118
|
end
|
119
|
+
|
120
|
+
def create_key_in_subclasses(*args)
|
121
|
+
return if subclasses.blank?
|
132
122
|
|
133
|
-
|
134
|
-
|
123
|
+
subclasses.each do |subclass|
|
124
|
+
subclass.key(*args)
|
125
|
+
end
|
135
126
|
end
|
136
127
|
|
137
|
-
def
|
128
|
+
def create_validations_for(key)
|
138
129
|
attribute = key.name.to_sym
|
139
130
|
|
140
131
|
if key.options[:required]
|
@@ -169,6 +160,10 @@ module MongoMapper
|
|
169
160
|
end
|
170
161
|
|
171
162
|
module InstanceMethods
|
163
|
+
def logger
|
164
|
+
self.class.logger
|
165
|
+
end
|
166
|
+
|
172
167
|
def initialize(attrs={})
|
173
168
|
unless attrs.nil?
|
174
169
|
self.class.associations.each_pair do |name, association|
|
@@ -42,10 +42,21 @@ module MongoMapper
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
OptionKeys = [:fields, :select, :skip, :offset, :limit, :sort, :order]
|
46
|
+
|
45
47
|
def initialize(options)
|
46
48
|
raise ArgumentError, "FinderOptions must be a hash" unless options.is_a?(Hash)
|
47
|
-
|
48
|
-
|
49
|
+
|
50
|
+
options = options.symbolize_keys
|
51
|
+
@options, @conditions = {}, options.delete(:conditions) || {}
|
52
|
+
|
53
|
+
options.each_pair do |key, value|
|
54
|
+
if OptionKeys.include?(key)
|
55
|
+
@options[key] = value
|
56
|
+
else
|
57
|
+
@conditions[key] = value
|
58
|
+
end
|
59
|
+
end
|
49
60
|
end
|
50
61
|
|
51
62
|
def criteria
|
data/lib/mongo_mapper/support.rb
CHANGED
data/mongo_mapper.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{mongo_mapper}
|
8
|
-
s.version = "0.5.
|
8
|
+
s.version = "0.5.3"
|
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-
|
12
|
+
s.date = %q{2009-10-11}
|
13
13
|
s.default_executable = %q{mmconsole}
|
14
14
|
s.email = %q{nunemaker@gmail.com}
|
15
15
|
s.executables = ["mmconsole"]
|
@@ -142,20 +142,20 @@ Gem::Specification.new do |s|
|
|
142
142
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
143
143
|
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
144
144
|
s.add_runtime_dependency(%q<mongo>, ["= 0.15.1"])
|
145
|
-
s.add_runtime_dependency(%q<jnunemaker-validatable>, ["= 1.7.
|
145
|
+
s.add_runtime_dependency(%q<jnunemaker-validatable>, ["= 1.7.4"])
|
146
146
|
s.add_development_dependency(%q<mocha>, ["= 0.9.4"])
|
147
147
|
s.add_development_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
|
148
148
|
else
|
149
149
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
150
150
|
s.add_dependency(%q<mongo>, ["= 0.15.1"])
|
151
|
-
s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.
|
151
|
+
s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.4"])
|
152
152
|
s.add_dependency(%q<mocha>, ["= 0.9.4"])
|
153
153
|
s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
|
154
154
|
end
|
155
155
|
else
|
156
156
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
157
157
|
s.add_dependency(%q<mongo>, ["= 0.15.1"])
|
158
|
-
s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.
|
158
|
+
s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.4"])
|
159
159
|
s.add_dependency(%q<mocha>, ["= 0.9.4"])
|
160
160
|
s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
|
161
161
|
end
|
data/test/custom_matchers.rb
CHANGED
@@ -45,4 +45,11 @@ module CustomMatchers
|
|
45
45
|
actual == expected_message
|
46
46
|
end
|
47
47
|
end
|
48
|
+
|
49
|
+
custom_matcher :have_index do |receiver, matcher, args|
|
50
|
+
index_name = args[0]
|
51
|
+
matcher.positive_failure_message = "#{receiver} does not have index named #{index_name}, but should"
|
52
|
+
matcher.negative_failure_message = "#{receiver} does have index named #{index_name}, but should not"
|
53
|
+
!receiver.collection.index_information.detect { |index| index[0] == index_name }.nil?
|
54
|
+
end
|
48
55
|
end
|
@@ -9,7 +9,8 @@ class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
|
|
9
9
|
|
10
10
|
should "default to nil" do
|
11
11
|
status = Status.new
|
12
|
-
status.target.should
|
12
|
+
status.target.nil?.should be_true
|
13
|
+
status.target.inspect.should == "nil"
|
13
14
|
end
|
14
15
|
|
15
16
|
should "be able to replace the association" do
|
@@ -19,7 +20,7 @@ class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
|
|
19
20
|
status.save.should be_true
|
20
21
|
|
21
22
|
from_db = Status.find(status.id)
|
22
|
-
from_db.target.
|
23
|
+
from_db.target.nil?.should be_false
|
23
24
|
from_db.target_id.should == project.id
|
24
25
|
from_db.target_type.should == "Project"
|
25
26
|
from_db.target.name.should == "mongomapper"
|
@@ -33,9 +34,9 @@ class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
|
|
33
34
|
|
34
35
|
from_db = Status.find(status.id)
|
35
36
|
from_db.target = nil
|
36
|
-
from_db.target_type.should
|
37
|
-
from_db.target_id.should
|
38
|
-
from_db.target.should
|
37
|
+
from_db.target_type.nil?.should be_true
|
38
|
+
from_db.target_id.nil?.should be_true
|
39
|
+
from_db.target.nil?.should be_true
|
39
40
|
end
|
40
41
|
|
41
42
|
context "association id set but document not found" do
|
@@ -48,7 +49,7 @@ class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
|
|
48
49
|
end
|
49
50
|
|
50
51
|
should "return nil instead of raising error" do
|
51
|
-
@status.target.should
|
52
|
+
@status.target.nil?.should be_true
|
52
53
|
end
|
53
54
|
end
|
54
55
|
end
|
@@ -9,7 +9,8 @@ class BelongsToProxyTest < Test::Unit::TestCase
|
|
9
9
|
|
10
10
|
should "default to nil" do
|
11
11
|
status = Status.new
|
12
|
-
status.project.should
|
12
|
+
status.project.nil?.should == true
|
13
|
+
status.project.inspect.should == 'nil'
|
13
14
|
end
|
14
15
|
|
15
16
|
should "be able to replace the association" do
|
@@ -19,7 +20,7 @@ class BelongsToProxyTest < Test::Unit::TestCase
|
|
19
20
|
status.save.should be_true
|
20
21
|
|
21
22
|
from_db = Status.find(status.id)
|
22
|
-
from_db.project.
|
23
|
+
from_db.project.nil?.should be_false
|
23
24
|
from_db.project.name.should == "mongomapper"
|
24
25
|
end
|
25
26
|
|
@@ -31,7 +32,8 @@ class BelongsToProxyTest < Test::Unit::TestCase
|
|
31
32
|
|
32
33
|
from_db = Status.find(status.id)
|
33
34
|
from_db.project = nil
|
34
|
-
from_db.project.should
|
35
|
+
from_db.project.nil?.should be_true
|
36
|
+
from_db.project.inspect.should == 'nil'
|
35
37
|
end
|
36
38
|
|
37
39
|
context "association id set but document not found" do
|
@@ -40,7 +42,8 @@ class BelongsToProxyTest < Test::Unit::TestCase
|
|
40
42
|
end
|
41
43
|
|
42
44
|
should "return nil instead of raising error" do
|
43
|
-
@status.project.should
|
45
|
+
@status.project.nil?.should be_true
|
46
|
+
@status.project.inspect.should == 'nil'
|
44
47
|
end
|
45
48
|
end
|
46
49
|
end
|
@@ -141,6 +141,27 @@ class DocumentTest < Test::Unit::TestCase
|
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
144
|
+
context "Using key with custom type with default" do
|
145
|
+
setup do
|
146
|
+
@document.key :window, WindowSize, :default => WindowSize.new(600, 480)
|
147
|
+
end
|
148
|
+
|
149
|
+
should "default to default" do
|
150
|
+
doc = @document.new
|
151
|
+
doc.window.should == WindowSize.new(600, 480)
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
should "save and load from mongo" do
|
156
|
+
doc = @document.new
|
157
|
+
doc.save
|
158
|
+
|
159
|
+
from_db = @document.find(doc.id)
|
160
|
+
from_db.window.should == WindowSize.new(600, 480)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
144
165
|
context "Creating a single document" do
|
145
166
|
setup do
|
146
167
|
@doc_instance = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
|
@@ -294,7 +315,12 @@ class DocumentTest < Test::Unit::TestCase
|
|
294
315
|
@document.find([@doc1.id]).should == [@doc1]
|
295
316
|
end
|
296
317
|
end
|
297
|
-
|
318
|
+
|
319
|
+
should "be able to find using condition auto-detection" do
|
320
|
+
@document.first(:first_name => 'John').should == @doc1
|
321
|
+
@document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
|
322
|
+
end
|
323
|
+
|
298
324
|
context "with :all" do
|
299
325
|
should "find all documents" do
|
300
326
|
@document.find(:all, :order => 'first_name').should == [@doc1, @doc3, @doc2]
|
@@ -693,39 +719,31 @@ class DocumentTest < Test::Unit::TestCase
|
|
693
719
|
end
|
694
720
|
|
695
721
|
should "allow creating index for a key" do
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
index_name.should == 'first_name_1'
|
702
|
-
index = @document.collection.index_information[index_name]
|
703
|
-
index.should_not be_nil
|
704
|
-
index.should include(['first_name', 1])
|
722
|
+
@document.ensure_index :first_name
|
723
|
+
MongoMapper.ensure_indexes!
|
724
|
+
|
725
|
+
@document.should have_index('first_name_1')
|
705
726
|
end
|
706
727
|
|
707
728
|
should "allow creating unique index for a key" do
|
708
|
-
@document.collection.expects(:create_index).with(:first_name, true)
|
709
729
|
@document.ensure_index :first_name, :unique => true
|
730
|
+
MongoMapper.ensure_indexes!
|
731
|
+
|
732
|
+
@document.should have_index('first_name_1')
|
710
733
|
end
|
711
734
|
|
712
735
|
should "allow creating index on multiple keys" do
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
[ 'first_name_1_last_name_-1', 'last_name_-1_first_name_1' ].should include(index_name)
|
719
|
-
|
720
|
-
index = @document.collection.index_information[index_name]
|
721
|
-
index.should_not be_nil
|
722
|
-
index.should include(['first_name', 1])
|
723
|
-
index.should include(['last_name', -1])
|
736
|
+
@document.ensure_index [[:first_name, 1], [:last_name, -1]]
|
737
|
+
MongoMapper.ensure_indexes!
|
738
|
+
|
739
|
+
@document.should have_index('last_name_-1_first_name_1')
|
724
740
|
end
|
725
741
|
|
726
742
|
should "work with :index shortcut when defining key" do
|
727
|
-
@document.expects(:ensure_index).with('father').returns(nil)
|
728
743
|
@document.key :father, String, :index => true
|
744
|
+
MongoMapper.ensure_indexes!
|
745
|
+
|
746
|
+
@document.should have_index('father_1')
|
729
747
|
end
|
730
748
|
end
|
731
749
|
end # Document Class Methods
|
@@ -918,6 +936,57 @@ class DocumentTest < Test::Unit::TestCase
|
|
918
936
|
end
|
919
937
|
end
|
920
938
|
end
|
939
|
+
|
940
|
+
context "Single collection inheritance" do
|
941
|
+
setup do
|
942
|
+
class ::DocParent
|
943
|
+
include MongoMapper::Document
|
944
|
+
key :_type, String
|
945
|
+
end
|
946
|
+
|
947
|
+
class ::DocChild < ::DocParent; end
|
948
|
+
DocParent.collection.clear
|
949
|
+
|
950
|
+
@parent = DocParent.new({:name => "Daddy Warbucks"})
|
951
|
+
@child = DocChild.new({:name => "Little Orphan Annie"})
|
952
|
+
end
|
953
|
+
|
954
|
+
teardown do
|
955
|
+
Object.send :remove_const, 'DocParent' if defined?(::DocParent)
|
956
|
+
Object.send :remove_const, 'DocChild' if defined?(::DocChild)
|
957
|
+
end
|
958
|
+
|
959
|
+
should "use the same collection in the subclass" do
|
960
|
+
DocChild.collection.name.should == DocParent.collection.name
|
961
|
+
end
|
962
|
+
|
963
|
+
should "assign the class name into the _type property" do
|
964
|
+
@parent._type.should == 'DocParent'
|
965
|
+
@child._type.should == 'DocChild'
|
966
|
+
end
|
967
|
+
|
968
|
+
should "load the document with the assigned type" do
|
969
|
+
@parent.save
|
970
|
+
@child.save
|
971
|
+
|
972
|
+
collection = DocParent.find(:all)
|
973
|
+
collection.size.should == 2
|
974
|
+
collection.first.should be_kind_of(DocParent)
|
975
|
+
collection.first.name.should == "Daddy Warbucks"
|
976
|
+
collection.last.should be_kind_of(DocChild)
|
977
|
+
collection.last.name.should == "Little Orphan Annie"
|
978
|
+
end
|
979
|
+
|
980
|
+
should "gracefully handle when the type can't be constantized" do
|
981
|
+
doc = DocParent.new(:name => 'Nunes')
|
982
|
+
doc._type = 'FoobarBaz'
|
983
|
+
doc.save
|
984
|
+
|
985
|
+
collection = DocParent.all
|
986
|
+
collection.last.should == doc
|
987
|
+
collection.last.should be_kind_of(DocParent)
|
988
|
+
end
|
989
|
+
end
|
921
990
|
|
922
991
|
context "timestamping" do
|
923
992
|
setup do
|
@@ -956,4 +1025,27 @@ class DocumentTest < Test::Unit::TestCase
|
|
956
1025
|
from_db.updated_at.to_i.should_not == old_updated_at.to_i
|
957
1026
|
end
|
958
1027
|
end
|
1028
|
+
|
1029
|
+
context "#exist?" do
|
1030
|
+
setup do
|
1031
|
+
@doc = @document.create(:first_name => "James", :age => 27)
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
should "be true when at least one document exists" do
|
1035
|
+
@document.exists?.should == true
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
should "be false when no documents exist" do
|
1039
|
+
@doc.destroy
|
1040
|
+
@document.exists?.should == false
|
1041
|
+
end
|
1042
|
+
|
1043
|
+
should "be true when at least one document exists that matches the conditions" do
|
1044
|
+
@document.exists?(:first_name => "James").should == true
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
should "be false when no documents exist with the provided conditions" do
|
1048
|
+
@document.exists?(:first_name => "Jean").should == false
|
1049
|
+
end
|
1050
|
+
end
|
959
1051
|
end
|
data/test/models.rb
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
# custom type
|
2
|
+
class WindowSize
|
3
|
+
attr_reader :width, :height
|
4
|
+
|
5
|
+
def self.to_mongo(value)
|
6
|
+
value.to_a
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.from_mongo(value)
|
10
|
+
value.is_a?(self) ? value : WindowSize.new(value)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(*args)
|
14
|
+
@width, @height = args.flatten
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_a
|
18
|
+
[width, height]
|
19
|
+
end
|
20
|
+
|
21
|
+
def ==(other)
|
22
|
+
other.is_a?(self.class) && other.width == width && other.height == height
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
1
27
|
class Post
|
2
28
|
include MongoMapper::Document
|
3
29
|
|
data/test/unit/test_document.rb
CHANGED
@@ -8,8 +8,14 @@ class DocumentTest < Test::Unit::TestCase
|
|
8
8
|
include MongoMapper::Document
|
9
9
|
set_collection_name 'test'
|
10
10
|
end
|
11
|
+
@document.collection.clear
|
11
12
|
end
|
12
|
-
|
13
|
+
|
14
|
+
should "have logger method" do
|
15
|
+
@document.logger.should == MongoMapper.logger
|
16
|
+
@document.logger.should be_instance_of(Logger)
|
17
|
+
end
|
18
|
+
|
13
19
|
should "track its descendants" do
|
14
20
|
MongoMapper::Document.descendants.should include(@document)
|
15
21
|
end
|
@@ -87,6 +93,12 @@ class DocumentTest < Test::Unit::TestCase
|
|
87
93
|
end
|
88
94
|
@document.collection.clear
|
89
95
|
end
|
96
|
+
|
97
|
+
should "have access to logger" do
|
98
|
+
doc = @document.new
|
99
|
+
doc.logger.should == @document.logger
|
100
|
+
doc.logger.should be_instance_of(Logger)
|
101
|
+
end
|
90
102
|
|
91
103
|
should "have access to the class's collection" do
|
92
104
|
doc = @document.new
|
@@ -99,6 +111,13 @@ class DocumentTest < Test::Unit::TestCase
|
|
99
111
|
@document.new.active.should be_true
|
100
112
|
@document.new(:active => false).active.should be_false
|
101
113
|
end
|
114
|
+
|
115
|
+
should "use default values if defined even when custom data type" do
|
116
|
+
@document.key :window, WindowSize, :default => WindowSize.new(600, 480)
|
117
|
+
|
118
|
+
doc = @document.new
|
119
|
+
doc.window.should == WindowSize.new(600, 480)
|
120
|
+
end
|
102
121
|
|
103
122
|
context "root document" do
|
104
123
|
should "have a nil _root_document" do
|
@@ -40,6 +40,11 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
should "give class access to logger" do
|
44
|
+
@klass.logger.should == MongoMapper.logger
|
45
|
+
@klass.logger.should be_instance_of(Logger)
|
46
|
+
end
|
47
|
+
|
43
48
|
should "add _id key" do
|
44
49
|
@klass.keys['_id'].should_not be_nil
|
45
50
|
end
|
@@ -284,6 +289,12 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
|
|
284
289
|
end
|
285
290
|
end
|
286
291
|
|
292
|
+
should "have access to class logger" do
|
293
|
+
doc = @document.new
|
294
|
+
doc.logger.should == @document.logger
|
295
|
+
doc.logger.should be_instance_of(Logger)
|
296
|
+
end
|
297
|
+
|
287
298
|
should "automatically have an _id key" do
|
288
299
|
@document.keys.keys.should include('_id')
|
289
300
|
end
|
@@ -8,7 +8,7 @@ class FinderOptionsTest < Test::Unit::TestCase
|
|
8
8
|
lambda { FinderOptions.new(1) }.should raise_error(ArgumentError)
|
9
9
|
end
|
10
10
|
|
11
|
-
should "
|
11
|
+
should "symbolize the keys of the hash provided" do
|
12
12
|
FinderOptions.new('offset' => 1).options.keys.map do |key|
|
13
13
|
key.should be_instance_of(Symbol)
|
14
14
|
end
|
@@ -179,4 +179,83 @@ class FinderOptionsTest < Test::Unit::TestCase
|
|
179
179
|
FinderOptions.new(:select => %w(a b)).options[:fields].should == %w(a b)
|
180
180
|
end
|
181
181
|
end
|
182
|
+
|
183
|
+
context "Condition auto-detection" do
|
184
|
+
should "know :conditions are criteria" do
|
185
|
+
finder = FinderOptions.new(:conditions => {:foo => 'bar'})
|
186
|
+
finder.criteria.should == {:foo => 'bar'}
|
187
|
+
finder.options.keys.should_not include(:conditions)
|
188
|
+
end
|
189
|
+
|
190
|
+
should "know fields is an option" do
|
191
|
+
finder = FinderOptions.new(:fields => ['foo'])
|
192
|
+
finder.options[:fields].should == ['foo']
|
193
|
+
finder.criteria.keys.should_not include(:fields)
|
194
|
+
end
|
195
|
+
|
196
|
+
# select gets converted to fields so just checking keys
|
197
|
+
should "know select is an option" do
|
198
|
+
finder = FinderOptions.new(:select => 'foo')
|
199
|
+
finder.options.keys.should include(:sort)
|
200
|
+
finder.criteria.keys.should_not include(:select)
|
201
|
+
finder.criteria.keys.should_not include(:fields)
|
202
|
+
end
|
203
|
+
|
204
|
+
should "know skip is an option" do
|
205
|
+
finder = FinderOptions.new(:skip => 10)
|
206
|
+
finder.options[:skip].should == 10
|
207
|
+
finder.criteria.keys.should_not include(:skip)
|
208
|
+
end
|
209
|
+
|
210
|
+
# offset gets converted to skip so just checking keys
|
211
|
+
should "know offset is an option" do
|
212
|
+
finder = FinderOptions.new(:offset => 10)
|
213
|
+
finder.options.keys.should include(:skip)
|
214
|
+
finder.criteria.keys.should_not include(:skip)
|
215
|
+
finder.criteria.keys.should_not include(:offset)
|
216
|
+
end
|
217
|
+
|
218
|
+
should "know limit is an option" do
|
219
|
+
finder = FinderOptions.new(:limit => 10)
|
220
|
+
finder.options[:limit].should == 10
|
221
|
+
finder.criteria.keys.should_not include(:limit)
|
222
|
+
end
|
223
|
+
|
224
|
+
should "know sort is an option" do
|
225
|
+
finder = FinderOptions.new(:sort => [['foo', 1]])
|
226
|
+
finder.options[:sort].should == [['foo', 1]]
|
227
|
+
finder.criteria.keys.should_not include(:sort)
|
228
|
+
end
|
229
|
+
|
230
|
+
# order gets converted to sort so just checking keys
|
231
|
+
should "know order is an option" do
|
232
|
+
finder = FinderOptions.new(:order => 'foo')
|
233
|
+
finder.options.keys.should include(:sort)
|
234
|
+
finder.criteria.keys.should_not include(:sort)
|
235
|
+
end
|
236
|
+
|
237
|
+
should "work with full range of things" do
|
238
|
+
finder_options = FinderOptions.new({
|
239
|
+
:foo => 'bar',
|
240
|
+
:baz => true,
|
241
|
+
:sort => [['foo', 1]],
|
242
|
+
:fields => ['foo', 'baz'],
|
243
|
+
:limit => 10,
|
244
|
+
:skip => 10,
|
245
|
+
})
|
246
|
+
|
247
|
+
finder_options.criteria.should == {
|
248
|
+
:foo => 'bar',
|
249
|
+
:baz => true,
|
250
|
+
}
|
251
|
+
|
252
|
+
finder_options.options.should == {
|
253
|
+
:sort => [['foo', 1]],
|
254
|
+
:fields => ['foo', 'baz'],
|
255
|
+
:limit => 10,
|
256
|
+
:skip => 10,
|
257
|
+
}
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
182
261
|
end # FinderOptionsTest
|
data/test/unit/test_support.rb
CHANGED
@@ -225,9 +225,12 @@ class SupportTest < Test::Unit::TestCase
|
|
225
225
|
Time.to_mongo(Time.local(2009, 8, 15, 0, 0, 0)).zone.should == 'UTC'
|
226
226
|
end
|
227
227
|
|
228
|
+
should "be nil if blank string" do
|
229
|
+
Time.to_mongo('').should be_nil
|
230
|
+
end
|
231
|
+
|
228
232
|
should "not be nil if nil" do
|
229
|
-
|
230
|
-
Time.to_mongo(nil).should_not be_nil
|
233
|
+
Time.to_mongo(nil).should be_nil
|
231
234
|
end
|
232
235
|
end
|
233
236
|
|
@@ -244,6 +247,12 @@ class SupportTest < Test::Unit::TestCase
|
|
244
247
|
Time.zone = nil
|
245
248
|
end
|
246
249
|
|
250
|
+
should "be nil if blank string" do
|
251
|
+
Time.zone = 'Hawaii'
|
252
|
+
Time.to_mongo('').should be_nil
|
253
|
+
Time.zone = nil
|
254
|
+
end
|
255
|
+
|
247
256
|
should "be nil if nil" do
|
248
257
|
Time.zone = 'Hawaii'
|
249
258
|
Time.to_mongo(nil).should be_nil
|
@@ -256,6 +265,10 @@ class SupportTest < Test::Unit::TestCase
|
|
256
265
|
time = Time.now
|
257
266
|
Time.from_mongo(time).should == time
|
258
267
|
end
|
268
|
+
|
269
|
+
should "be nil if nil" do
|
270
|
+
Time.from_mongo(nil).should be_nil
|
271
|
+
end
|
259
272
|
end
|
260
273
|
|
261
274
|
context "Time#from_mongo with Time.zone" do
|
@@ -268,5 +281,11 @@ class SupportTest < Test::Unit::TestCase
|
|
268
281
|
|
269
282
|
Time.zone = nil
|
270
283
|
end
|
284
|
+
|
285
|
+
should "be nil if nil" do
|
286
|
+
Time.zone = 'Hawaii'
|
287
|
+
Time.from_mongo(nil).should be_nil
|
288
|
+
Time.zone = nil
|
289
|
+
end
|
271
290
|
end
|
272
291
|
end
|
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.
|
4
|
+
version: 0.5.3
|
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-
|
12
|
+
date: 2009-10-11 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.
|
43
|
+
version: 1.7.4
|
44
44
|
version:
|
45
45
|
- !ruby/object:Gem::Dependency
|
46
46
|
name: mocha
|