mongo_mapper 0.5.2 → 0.5.3
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/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
|