mongo_mapper 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +3 -1
- data/Rakefile +9 -12
- data/lib/mongo_mapper.rb +30 -10
- data/lib/mongo_mapper/document.rb +16 -74
- data/lib/mongo_mapper/embedded_document.rb +7 -1
- data/lib/mongo_mapper/plugins.rb +3 -0
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +1 -12
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +6 -1
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +4 -1
- data/lib/mongo_mapper/plugins/callbacks.rb +183 -12
- data/lib/mongo_mapper/plugins/keys.rb +17 -5
- data/lib/mongo_mapper/plugins/modifiers.rb +87 -0
- data/lib/mongo_mapper/plugins/pagination/proxy.rb +7 -3
- data/lib/mongo_mapper/plugins/protected.rb +1 -1
- data/lib/mongo_mapper/plugins/rails.rb +16 -8
- data/lib/mongo_mapper/plugins/serialization.rb +51 -81
- data/lib/mongo_mapper/plugins/timestamps.rb +21 -0
- data/lib/mongo_mapper/plugins/userstamps.rb +14 -0
- data/lib/mongo_mapper/query.rb +1 -1
- data/lib/mongo_mapper/version.rb +3 -0
- data/mongo_mapper.gemspec +22 -11
- data/test/active_model_lint_test.rb +11 -0
- data/test/functional/associations/test_in_array_proxy.rb +16 -0
- data/test/functional/associations/test_many_documents_proxy.rb +22 -0
- data/test/functional/test_callbacks.rb +104 -34
- data/test/functional/test_document.rb +70 -149
- data/test/functional/test_embedded_document.rb +39 -34
- data/test/functional/test_indexing.rb +44 -0
- data/test/functional/test_modifiers.rb +297 -227
- data/test/functional/test_protected.rb +11 -5
- data/test/functional/test_timestamps.rb +64 -0
- data/test/functional/test_userstamps.rb +28 -0
- data/test/support/timing.rb +1 -1
- data/test/unit/serializers/test_json_serializer.rb +30 -17
- data/test/unit/test_embedded_document.rb +15 -15
- data/test/unit/test_keys.rb +15 -11
- data/test/unit/test_mongo_mapper.rb +31 -1
- data/test/unit/test_pagination.rb +33 -0
- data/test/unit/test_query.rb +6 -0
- data/test/unit/test_serialization.rb +3 -3
- data/test/unit/test_support.rb +9 -5
- metadata +17 -6
- data/VERSION +0 -1
@@ -16,7 +16,7 @@ class ProtectedTest < Test::Unit::TestCase
|
|
16
16
|
should 'have protected attributes class method' do
|
17
17
|
@doc_class.protected_attributes.should == [:admin].to_set
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
should "default protected attributes to nil" do
|
21
21
|
Doc().protected_attributes.should be_nil
|
22
22
|
end
|
@@ -46,7 +46,7 @@ class ProtectedTest < Test::Unit::TestCase
|
|
46
46
|
doc = @doc_class.new(:name => 'John')
|
47
47
|
doc.admin = true
|
48
48
|
doc.save!
|
49
|
-
|
49
|
+
|
50
50
|
doc = @doc_class.first(:name => 'John')
|
51
51
|
doc.admin.should be_true
|
52
52
|
doc.name.should == 'John'
|
@@ -63,8 +63,14 @@ class ProtectedTest < Test::Unit::TestCase
|
|
63
63
|
@doc.name.should == 'Stimpson J. Cat'
|
64
64
|
@doc.admin.should be_false
|
65
65
|
end
|
66
|
+
|
67
|
+
should 'be indifferent to whether the protected keys are strings or symbols' do
|
68
|
+
@doc.update_attributes!("name" => 'Stimpson J. Cat', "admin" => true)
|
69
|
+
@doc.name.should == 'Stimpson J. Cat'
|
70
|
+
@doc.admin.should be_false
|
71
|
+
end
|
66
72
|
end
|
67
|
-
|
73
|
+
|
68
74
|
context "Single collection inherited protected attributes" do
|
69
75
|
setup do
|
70
76
|
class ::GrandParent
|
@@ -126,7 +132,7 @@ class ProtectedTest < Test::Unit::TestCase
|
|
126
132
|
should 'have protected attributes class method' do
|
127
133
|
@edoc_class.protected_attributes.should == [:admin].to_set
|
128
134
|
end
|
129
|
-
|
135
|
+
|
130
136
|
should "default protected attributes to nil" do
|
131
137
|
EDoc().protected_attributes.should be_nil
|
132
138
|
end
|
@@ -152,4 +158,4 @@ class ProtectedTest < Test::Unit::TestCase
|
|
152
158
|
@edoc.admin.should be_false
|
153
159
|
end
|
154
160
|
end
|
155
|
-
end
|
161
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TimestampsTest < Test::Unit::TestCase
|
4
|
+
context "timestamping" do
|
5
|
+
setup do
|
6
|
+
@klass = Doc do
|
7
|
+
set_collection_name 'users'
|
8
|
+
|
9
|
+
key :first_name, String
|
10
|
+
key :last_name, String
|
11
|
+
key :age, Integer
|
12
|
+
key :date, Date
|
13
|
+
end
|
14
|
+
@klass.timestamps!
|
15
|
+
end
|
16
|
+
|
17
|
+
should "set created_at and updated_at on create" do
|
18
|
+
doc = @klass.new(:first_name => 'John', :age => 27)
|
19
|
+
doc.created_at.should be(nil)
|
20
|
+
doc.updated_at.should be(nil)
|
21
|
+
doc.save
|
22
|
+
doc.created_at.should_not be(nil)
|
23
|
+
doc.updated_at.should_not be(nil)
|
24
|
+
end
|
25
|
+
|
26
|
+
should "not overwrite created_at if it already exists" do
|
27
|
+
original_created_at = 1.month.ago
|
28
|
+
doc = @klass.new(:first_name => 'John', :age => 27, :created_at => original_created_at)
|
29
|
+
doc.created_at.to_i.should == original_created_at.to_i
|
30
|
+
doc.updated_at.should be_nil
|
31
|
+
doc.save
|
32
|
+
doc.created_at.to_i.should == original_created_at.to_i
|
33
|
+
doc.updated_at.should_not be_nil
|
34
|
+
end
|
35
|
+
|
36
|
+
should "set updated_at on field update but leave created_at alone" do
|
37
|
+
doc = @klass.create(:first_name => 'John', :age => 27)
|
38
|
+
old_created_at = doc.created_at
|
39
|
+
old_updated_at = doc.updated_at
|
40
|
+
doc.first_name = 'Johnny'
|
41
|
+
|
42
|
+
Timecop.freeze(Time.now + 5.seconds) do
|
43
|
+
doc.save
|
44
|
+
end
|
45
|
+
|
46
|
+
doc.created_at.should == old_created_at
|
47
|
+
doc.updated_at.should_not == old_updated_at
|
48
|
+
end
|
49
|
+
|
50
|
+
should "set updated_at on document update but leave created_at alone" do
|
51
|
+
doc = @klass.create(:first_name => 'John', :age => 27)
|
52
|
+
old_created_at = doc.created_at
|
53
|
+
old_updated_at = doc.updated_at
|
54
|
+
|
55
|
+
Timecop.freeze(Time.now + 5.seconds) do
|
56
|
+
@klass.update(doc._id, { :first_name => 'Johnny' })
|
57
|
+
end
|
58
|
+
|
59
|
+
doc = doc.reload
|
60
|
+
doc.created_at.should == old_created_at
|
61
|
+
doc.updated_at.should_not == old_updated_at
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class UserstampsTest < Test::Unit::TestCase
|
4
|
+
context "userstamping" do
|
5
|
+
setup do
|
6
|
+
@document = Doc do
|
7
|
+
set_collection_name 'users'
|
8
|
+
userstamps!
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
should "add creator_id key" do
|
13
|
+
@document.keys.keys.should include('creator_id')
|
14
|
+
end
|
15
|
+
|
16
|
+
should "add updater_id key" do
|
17
|
+
@document.keys.keys.should include('updater_id')
|
18
|
+
end
|
19
|
+
|
20
|
+
should "add belongs_to creator" do
|
21
|
+
@document.associations.keys.should include('creator')
|
22
|
+
end
|
23
|
+
|
24
|
+
should "add belongs_to updater" do
|
25
|
+
@document.associations.keys.should include('updater')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/test/support/timing.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
require 'test_helper'
|
2
|
+
require 'active_support/version'
|
2
3
|
|
3
4
|
class JsonSerializationTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
# Helper function in case things change in the future
|
7
|
+
# - replacing all those to_json calls was a nightmare
|
8
|
+
def convert_to_json object, options = {}
|
9
|
+
ActiveSupport::JSON.encode(object, options)
|
10
|
+
end
|
11
|
+
|
4
12
|
class Tag
|
5
13
|
include MongoMapper::EmbeddedDocument
|
6
14
|
key :name, String
|
@@ -30,11 +38,11 @@ class JsonSerializationTest < Test::Unit::TestCase
|
|
30
38
|
|
31
39
|
should "include demodulized root" do
|
32
40
|
Contact.include_root_in_json = true
|
33
|
-
assert_match %r{^\{"contact"
|
41
|
+
assert_match %r{^\{"contact":\s?\{}, convert_to_json(@contact)
|
34
42
|
end
|
35
43
|
|
36
44
|
should "encode all encodable attributes" do
|
37
|
-
json = @contact
|
45
|
+
json = convert_to_json(@contact)
|
38
46
|
|
39
47
|
assert_no_match %r{"_id"}, json
|
40
48
|
assert_match %r{"name":"Konata Izumi"}, json
|
@@ -45,7 +53,7 @@ class JsonSerializationTest < Test::Unit::TestCase
|
|
45
53
|
end
|
46
54
|
|
47
55
|
should "allow attribute filtering with only" do
|
48
|
-
json = @contact
|
56
|
+
json = convert_to_json(@contact, :only => [:name, :age])
|
49
57
|
|
50
58
|
assert_no_match %r{"_id"}, json
|
51
59
|
assert_match %r{"name":"Konata Izumi"}, json
|
@@ -56,7 +64,7 @@ class JsonSerializationTest < Test::Unit::TestCase
|
|
56
64
|
end
|
57
65
|
|
58
66
|
should "allow attribute filtering with except" do
|
59
|
-
json = @contact
|
67
|
+
json = convert_to_json(@contact, :except => [:name, :age])
|
60
68
|
|
61
69
|
assert_no_match %r{"_id"}, json
|
62
70
|
assert_no_match %r{"name"}, json
|
@@ -68,12 +76,12 @@ class JsonSerializationTest < Test::Unit::TestCase
|
|
68
76
|
|
69
77
|
context "_id key" do
|
70
78
|
should "not be included by default" do
|
71
|
-
json = @contact
|
79
|
+
json = convert_to_json(@contact)
|
72
80
|
assert_no_match %r{"_id":}, json
|
73
81
|
end
|
74
82
|
|
75
83
|
should "not be included even if :except is used" do
|
76
|
-
json = @contact
|
84
|
+
json = convert_to_json(@contact, :except => :name)
|
77
85
|
assert_no_match %r{"_id":}, json
|
78
86
|
end
|
79
87
|
end
|
@@ -85,12 +93,12 @@ class JsonSerializationTest < Test::Unit::TestCase
|
|
85
93
|
end
|
86
94
|
|
87
95
|
should "be included by default" do
|
88
|
-
json = @contact
|
96
|
+
json = convert_to_json(@contact)
|
89
97
|
assert_match %r{"id"}, json
|
90
98
|
end
|
91
99
|
|
92
100
|
should "be included when single method included" do
|
93
|
-
json = @contact
|
101
|
+
json = convert_to_json(@contact, :methods => :label)
|
94
102
|
assert_match %r{"id"}, json
|
95
103
|
assert_match %r{"label":"Has cheezburger"}, json
|
96
104
|
assert_match %r{"name":"Konata Izumi"}, json
|
@@ -98,7 +106,7 @@ class JsonSerializationTest < Test::Unit::TestCase
|
|
98
106
|
end
|
99
107
|
|
100
108
|
should "be included when multiple methods included" do
|
101
|
-
json = @contact
|
109
|
+
json = convert_to_json(@contact, :methods => [:label, :favorite_quote])
|
102
110
|
assert_match %r{"id"}, json
|
103
111
|
assert_match %r{"label":"Has cheezburger"}, json
|
104
112
|
assert_match %r{"favorite_quote":"Constraints are liberating"}, json
|
@@ -106,9 +114,14 @@ class JsonSerializationTest < Test::Unit::TestCase
|
|
106
114
|
end
|
107
115
|
|
108
116
|
should "not be included if :only is present" do
|
109
|
-
json = @contact
|
117
|
+
json = convert_to_json(@contact, :only => :name)
|
110
118
|
assert_no_match %r{"id":}, json
|
111
119
|
end
|
120
|
+
|
121
|
+
should "be represented by a string" do
|
122
|
+
json = convert_to_json(@contact)
|
123
|
+
assert_match %r{"id":"}, json
|
124
|
+
end
|
112
125
|
end
|
113
126
|
|
114
127
|
context "including methods" do
|
@@ -118,12 +131,12 @@ class JsonSerializationTest < Test::Unit::TestCase
|
|
118
131
|
end
|
119
132
|
|
120
133
|
should "include single method" do
|
121
|
-
json = @contact
|
134
|
+
json = convert_to_json(@contact, :methods => :label)
|
122
135
|
assert_match %r{"label":"Has cheezburger"}, json
|
123
136
|
end
|
124
137
|
|
125
138
|
should "include multiple methods" do
|
126
|
-
json = @contact
|
139
|
+
json = convert_to_json(@contact, :only => :name, :methods => [:label, :favorite_quote])
|
127
140
|
assert_match %r{"label":"Has cheezburger"}, json
|
128
141
|
assert_match %r{"favorite_quote":"Constraints are liberating"}, json
|
129
142
|
assert_match %r{"name":"Konata Izumi"}, json
|
@@ -143,13 +156,13 @@ class JsonSerializationTest < Test::Unit::TestCase
|
|
143
156
|
end
|
144
157
|
|
145
158
|
should "allow attribute filtering with only" do
|
146
|
-
json =
|
159
|
+
json =convert_to_json(@contacts, :only => :name)
|
147
160
|
assert_match %r{\{"name":"David"\}}, json
|
148
161
|
assert_match %r{\{"name":"Mary"\}}, json
|
149
162
|
end
|
150
163
|
|
151
164
|
should "allow attribute filtering with except" do
|
152
|
-
json = @contacts
|
165
|
+
json = convert_to_json(@contacts, :except => [:name, :preferences, :awesome, :created_at, :updated_at])
|
153
166
|
assert_match %r{"age":39}, json
|
154
167
|
assert_match %r{"age":14}, json
|
155
168
|
assert_no_match %r{"name":}, json
|
@@ -165,7 +178,7 @@ class JsonSerializationTest < Test::Unit::TestCase
|
|
165
178
|
1 => Contact.new(:name => 'David', :age => 39),
|
166
179
|
2 => Contact.new(:name => 'Mary', :age => 14)
|
167
180
|
}
|
168
|
-
json = contacts
|
181
|
+
json = convert_to_json(contacts, :only => [1, :name])
|
169
182
|
assert_match %r{"1":}, json
|
170
183
|
assert_match %r{\{"name":"David"\}}, json
|
171
184
|
assert_no_match %r{"2":}, json
|
@@ -174,7 +187,7 @@ class JsonSerializationTest < Test::Unit::TestCase
|
|
174
187
|
should "include embedded attributes" do
|
175
188
|
contact = Contact.new(:name => 'John', :age => 27)
|
176
189
|
contact.tags = [Tag.new(:name => 'awesome'), Tag.new(:name => 'ruby')]
|
177
|
-
json = contact
|
190
|
+
json = convert_to_json(contact)
|
178
191
|
assert_match %r{"tags":}, json
|
179
192
|
assert_match %r{"name":"awesome"}, json
|
180
193
|
assert_match %r{"name":"ruby"}, json
|
@@ -183,7 +196,7 @@ class JsonSerializationTest < Test::Unit::TestCase
|
|
183
196
|
should "include dynamic attributes" do
|
184
197
|
contact = Contact.new(:name => 'John', :age => 27, :foo => 'bar')
|
185
198
|
contact['smell'] = 'stinky'
|
186
|
-
json = contact
|
199
|
+
json = convert_to_json(contact)
|
187
200
|
assert_match %r{"smell":"stinky"}, json
|
188
201
|
end
|
189
202
|
end
|
@@ -42,7 +42,7 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
|
|
42
42
|
Object.send :remove_const, 'Child' if defined?(::Child)
|
43
43
|
Object.send :remove_const, 'OtherChild' if defined?(::OtherChild)
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
context "Including MongoMapper::EmbeddedDocument in a class" do
|
47
47
|
setup do
|
48
48
|
@klass = EDoc()
|
@@ -249,34 +249,34 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
|
|
249
249
|
|
250
250
|
should "convert string object id to mongo object id when assigning id with _id object id type" do
|
251
251
|
id = Mongo::ObjectID.new
|
252
|
-
|
253
252
|
doc = @document.new(:id => id.to_s)
|
254
253
|
doc._id.should == id
|
255
|
-
doc.id.should
|
256
|
-
|
254
|
+
doc.id.should == id
|
257
255
|
doc = @document.new(:_id => id.to_s)
|
258
256
|
doc._id.should == id
|
259
|
-
doc.id.should
|
257
|
+
doc.id.should == id
|
260
258
|
end
|
261
259
|
|
262
|
-
context "
|
260
|
+
context "_parent_document" do
|
263
261
|
should "default to nil" do
|
262
|
+
@document.new._parent_document.should be_nil
|
264
263
|
@document.new._root_document.should be_nil
|
265
264
|
end
|
266
265
|
|
267
|
-
should "
|
266
|
+
should "set _root_document when setting _parent_document" do
|
268
267
|
root = Doc().new
|
269
|
-
doc = @document.new
|
270
|
-
|
268
|
+
doc = @document.new(:_parent_document => root)
|
269
|
+
doc._parent_document.should be(root)
|
271
270
|
doc._root_document.should be(root)
|
272
271
|
end
|
273
272
|
|
274
|
-
should "
|
275
|
-
root
|
276
|
-
klass
|
277
|
-
|
278
|
-
|
279
|
-
|
273
|
+
should "set _root_document when setting _parent_document on embedded many" do
|
274
|
+
root = Doc().new
|
275
|
+
klass = EDoc { many :children }
|
276
|
+
parent = klass.new(:_parent_document => root, :children => [{}])
|
277
|
+
child = parent.children.first
|
278
|
+
child._parent_document.should be(parent)
|
279
|
+
child._root_document.should be(root)
|
280
280
|
end
|
281
281
|
end
|
282
282
|
|
data/test/unit/test_keys.rb
CHANGED
@@ -42,25 +42,25 @@ class KeyTest < Test::Unit::TestCase
|
|
42
42
|
should "symbolize option keys" do
|
43
43
|
Key.new(:foo, Integer, 'required' => true).options[:required].should be(true)
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
should "work with just name" do
|
47
47
|
key = Key.new(:foo)
|
48
48
|
key.name.should == 'foo'
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
should "work with name and type" do
|
52
52
|
key = Key.new(:foo, String)
|
53
53
|
key.name.should == 'foo'
|
54
54
|
key.type.should == String
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
should "work with name, type, and options" do
|
58
58
|
key = Key.new(:foo, String, :required => true)
|
59
59
|
key.name.should == 'foo'
|
60
60
|
key.type.should == String
|
61
61
|
key.options[:required].should be_true
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
should "work with name and options" do
|
65
65
|
key = Key.new(:foo, :required => true)
|
66
66
|
key.name.should == 'foo'
|
@@ -80,7 +80,7 @@ class KeyTest < Test::Unit::TestCase
|
|
80
80
|
should "not be equal to another key with different type" do
|
81
81
|
Key.new(:name, String).should_not == Key.new(:name, Integer)
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
should "know if it is a embedded_document" do
|
85
85
|
Key.new(:name, EDoc()).embeddable?.should be_true
|
86
86
|
end
|
@@ -88,12 +88,12 @@ class KeyTest < Test::Unit::TestCase
|
|
88
88
|
should "know if it is not a embedded_document" do
|
89
89
|
Key.new(:name, String).embeddable?.should be_false
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
should "know if it is a number" do
|
93
93
|
Key.new(:age, Integer).number?.should be_true
|
94
94
|
Key.new(:age, Float).number?.should be_true
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
97
|
should "know if it is not a number" do
|
98
98
|
Key.new(:age, String).number?.should be_false
|
99
99
|
end
|
@@ -110,7 +110,7 @@ class KeyTest < Test::Unit::TestCase
|
|
110
110
|
key.set(FooType.new('something')).should == 'to_mongo'
|
111
111
|
end
|
112
112
|
end
|
113
|
-
|
113
|
+
|
114
114
|
context "getting a value with a custom type" do
|
115
115
|
should "use #from_mongo to convert back to custom type" do
|
116
116
|
key = Key.new(:foo, FooType)
|
@@ -123,7 +123,7 @@ class KeyTest < Test::Unit::TestCase
|
|
123
123
|
key = Key.new(:foo, String)
|
124
124
|
key.get('bar').should == 'bar'
|
125
125
|
end
|
126
|
-
|
126
|
+
|
127
127
|
should "work without type" do
|
128
128
|
key = Key.new(:foo)
|
129
129
|
key.get([1, '2']).should == [1, '2']
|
@@ -144,7 +144,7 @@ class KeyTest < Test::Unit::TestCase
|
|
144
144
|
end
|
145
145
|
end
|
146
146
|
end
|
147
|
-
|
147
|
+
|
148
148
|
context "getting a value with a default set" do
|
149
149
|
setup do
|
150
150
|
@key = Key.new(:foo, String, :default => 'baz')
|
@@ -157,7 +157,7 @@ class KeyTest < Test::Unit::TestCase
|
|
157
157
|
should "return value if not blank" do
|
158
158
|
@key.get('foobar').should == 'foobar'
|
159
159
|
end
|
160
|
-
|
160
|
+
|
161
161
|
should "work with Boolean type and false value" do
|
162
162
|
Key.new(:active, Boolean, :default => false).get(nil).should be_false
|
163
163
|
end
|
@@ -165,5 +165,9 @@ class KeyTest < Test::Unit::TestCase
|
|
165
165
|
should "work with Boolean type and true value" do
|
166
166
|
Key.new(:active, Boolean, :default => true).get(nil).should be_true
|
167
167
|
end
|
168
|
+
|
169
|
+
should "work with procs" do
|
170
|
+
Key.new(:foo, String, :default => lambda { return 'hello world' }).get(nil).should == "hello world"
|
171
|
+
end
|
168
172
|
end
|
169
173
|
end # KeyTest
|