lookout-mongo_mapper 0.11.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/LICENSE +20 -0
- data/README.rdoc +33 -0
- data/UPGRADES +26 -0
- data/bin/mmconsole +59 -0
- data/examples/attr_accessible.rb +22 -0
- data/examples/attr_protected.rb +22 -0
- data/examples/cache_key.rb +24 -0
- data/examples/custom_types.rb +24 -0
- data/examples/identity_map.rb +33 -0
- data/examples/identity_map/automatic.rb +2 -0
- data/examples/keys.rb +40 -0
- data/examples/modifiers/set.rb +25 -0
- data/examples/plugins.rb +38 -0
- data/examples/querying.rb +35 -0
- data/examples/safe.rb +43 -0
- data/examples/scopes.rb +52 -0
- data/examples/validating/embedded_docs.rb +29 -0
- data/lib/mongo_mapper.rb +94 -0
- data/lib/mongo_mapper/connection.rb +96 -0
- data/lib/mongo_mapper/document.rb +42 -0
- data/lib/mongo_mapper/embedded_document.rb +32 -0
- data/lib/mongo_mapper/exceptions.rb +30 -0
- data/lib/mongo_mapper/extensions/array.rb +19 -0
- data/lib/mongo_mapper/extensions/binary.rb +22 -0
- data/lib/mongo_mapper/extensions/boolean.rb +44 -0
- data/lib/mongo_mapper/extensions/date.rb +25 -0
- data/lib/mongo_mapper/extensions/float.rb +14 -0
- data/lib/mongo_mapper/extensions/hash.rb +14 -0
- data/lib/mongo_mapper/extensions/integer.rb +19 -0
- data/lib/mongo_mapper/extensions/kernel.rb +9 -0
- data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
- data/lib/mongo_mapper/extensions/object.rb +26 -0
- data/lib/mongo_mapper/extensions/object_id.rb +32 -0
- data/lib/mongo_mapper/extensions/set.rb +20 -0
- data/lib/mongo_mapper/extensions/string.rb +18 -0
- data/lib/mongo_mapper/extensions/time.rb +28 -0
- data/lib/mongo_mapper/locale/en.yml +5 -0
- data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
- data/lib/mongo_mapper/plugins.rb +22 -0
- data/lib/mongo_mapper/plugins/accessible.rb +52 -0
- data/lib/mongo_mapper/plugins/active_model.rb +18 -0
- data/lib/mongo_mapper/plugins/associations.rb +90 -0
- data/lib/mongo_mapper/plugins/associations/base.rb +92 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +54 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +34 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +52 -0
- data/lib/mongo_mapper/plugins/associations/collection.rb +27 -0
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +44 -0
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +133 -0
- data/lib/mongo_mapper/plugins/associations/many_association.rb +63 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +118 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
- data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
- data/lib/mongo_mapper/plugins/associations/one_as_proxy.rb +22 -0
- data/lib/mongo_mapper/plugins/associations/one_association.rb +48 -0
- data/lib/mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb +30 -0
- data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +44 -0
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +95 -0
- data/lib/mongo_mapper/plugins/associations/proxy.rb +134 -0
- data/lib/mongo_mapper/plugins/associations/single_association.rb +46 -0
- data/lib/mongo_mapper/plugins/caching.rb +21 -0
- data/lib/mongo_mapper/plugins/callbacks.rb +29 -0
- data/lib/mongo_mapper/plugins/clone.rb +22 -0
- data/lib/mongo_mapper/plugins/dirty.rb +60 -0
- data/lib/mongo_mapper/plugins/document.rb +41 -0
- data/lib/mongo_mapper/plugins/dynamic_querying.rb +45 -0
- data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
- data/lib/mongo_mapper/plugins/embedded_callbacks.rb +56 -0
- data/lib/mongo_mapper/plugins/embedded_document.rb +53 -0
- data/lib/mongo_mapper/plugins/equality.rb +23 -0
- data/lib/mongo_mapper/plugins/identity_map.rb +128 -0
- data/lib/mongo_mapper/plugins/indexes.rb +13 -0
- data/lib/mongo_mapper/plugins/inspect.rb +16 -0
- data/lib/mongo_mapper/plugins/keys.rb +313 -0
- data/lib/mongo_mapper/plugins/keys/key.rb +61 -0
- data/lib/mongo_mapper/plugins/logger.rb +18 -0
- data/lib/mongo_mapper/plugins/modifiers.rb +134 -0
- data/lib/mongo_mapper/plugins/pagination.rb +16 -0
- data/lib/mongo_mapper/plugins/persistence.rb +69 -0
- data/lib/mongo_mapper/plugins/protected.rb +45 -0
- data/lib/mongo_mapper/plugins/querying.rb +165 -0
- data/lib/mongo_mapper/plugins/querying/decorator.rb +36 -0
- data/lib/mongo_mapper/plugins/rails.rb +58 -0
- data/lib/mongo_mapper/plugins/rails/active_record_association_adapter.rb +33 -0
- data/lib/mongo_mapper/plugins/safe.rb +28 -0
- data/lib/mongo_mapper/plugins/sci.rb +36 -0
- data/lib/mongo_mapper/plugins/scopes.rb +27 -0
- data/lib/mongo_mapper/plugins/serialization.rb +109 -0
- data/lib/mongo_mapper/plugins/timestamps.rb +22 -0
- data/lib/mongo_mapper/plugins/touch.rb +18 -0
- data/lib/mongo_mapper/plugins/userstamps.rb +18 -0
- data/lib/mongo_mapper/plugins/validations.rb +86 -0
- data/lib/mongo_mapper/railtie.rb +48 -0
- data/lib/mongo_mapper/railtie/database.rake +65 -0
- data/lib/mongo_mapper/translation.rb +10 -0
- data/lib/mongo_mapper/version.rb +4 -0
- data/lib/rails/generators/mongo_mapper/config/config_generator.rb +24 -0
- data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +18 -0
- data/lib/rails/generators/mongo_mapper/model/model_generator.rb +23 -0
- data/lib/rails/generators/mongo_mapper/model/templates/model.rb +13 -0
- data/test/_NOTE_ON_TESTING +1 -0
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +64 -0
- data/test/functional/associations/test_belongs_to_proxy.rb +238 -0
- data/test/functional/associations/test_in_array_proxy.rb +349 -0
- data/test/functional/associations/test_many_documents_as_proxy.rb +231 -0
- data/test/functional/associations/test_many_documents_proxy.rb +866 -0
- data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +239 -0
- data/test/functional/associations/test_many_embedded_proxy.rb +289 -0
- data/test/functional/associations/test_many_polymorphic_proxy.rb +303 -0
- data/test/functional/associations/test_one_as_proxy.rb +491 -0
- data/test/functional/associations/test_one_embedded_polymorphic_proxy.rb +208 -0
- data/test/functional/associations/test_one_embedded_proxy.rb +100 -0
- data/test/functional/associations/test_one_proxy.rb +383 -0
- data/test/functional/test_accessible.rb +198 -0
- data/test/functional/test_associations.rb +46 -0
- data/test/functional/test_binary.rb +27 -0
- data/test/functional/test_caching.rb +77 -0
- data/test/functional/test_callbacks.rb +232 -0
- data/test/functional/test_dirty.rb +301 -0
- data/test/functional/test_document.rb +282 -0
- data/test/functional/test_dynamic_querying.rb +75 -0
- data/test/functional/test_embedded_document.rb +288 -0
- data/test/functional/test_equality.rb +20 -0
- data/test/functional/test_identity_map.rb +513 -0
- data/test/functional/test_indexes.rb +50 -0
- data/test/functional/test_logger.rb +20 -0
- data/test/functional/test_modifiers.rb +537 -0
- data/test/functional/test_pagination.rb +91 -0
- data/test/functional/test_protected.rb +201 -0
- data/test/functional/test_querying.rb +935 -0
- data/test/functional/test_safe.rb +76 -0
- data/test/functional/test_sci.rb +240 -0
- data/test/functional/test_scopes.rb +171 -0
- data/test/functional/test_timestamps.rb +62 -0
- data/test/functional/test_touch.rb +125 -0
- data/test/functional/test_userstamps.rb +44 -0
- data/test/functional/test_validations.rb +414 -0
- data/test/models.rb +261 -0
- data/test/support/railtie.rb +4 -0
- data/test/support/railtie/autoloaded.rb +2 -0
- data/test/support/railtie/not_autoloaded.rb +3 -0
- data/test/support/railtie/parent.rb +3 -0
- data/test/test_active_model_lint.rb +18 -0
- data/test/test_helper.rb +93 -0
- data/test/unit/associations/test_base.rb +146 -0
- data/test/unit/associations/test_belongs_to_association.rb +29 -0
- data/test/unit/associations/test_many_association.rb +63 -0
- data/test/unit/associations/test_one_association.rb +47 -0
- data/test/unit/associations/test_proxy.rb +100 -0
- data/test/unit/serializers/test_json_serializer.rb +216 -0
- data/test/unit/serializers/test_xml_serializer.rb +196 -0
- data/test/unit/test_clone.rb +69 -0
- data/test/unit/test_document.rb +249 -0
- data/test/unit/test_dynamic_finder.rb +125 -0
- data/test/unit/test_embedded_document.rb +682 -0
- data/test/unit/test_equality.rb +38 -0
- data/test/unit/test_exceptions.rb +12 -0
- data/test/unit/test_extensions.rb +380 -0
- data/test/unit/test_identity_map_middleware.rb +34 -0
- data/test/unit/test_inspect.rb +47 -0
- data/test/unit/test_key.rb +205 -0
- data/test/unit/test_keys.rb +65 -0
- data/test/unit/test_mongo_mapper.rb +143 -0
- data/test/unit/test_pagination.rb +11 -0
- data/test/unit/test_plugins.rb +89 -0
- data/test/unit/test_rails.rb +183 -0
- data/test/unit/test_rails_compatibility.rb +38 -0
- data/test/unit/test_rails_reflect_on_association.rb +118 -0
- data/test/unit/test_railtie.rb +66 -0
- data/test/unit/test_serialization.rb +166 -0
- data/test/unit/test_time_zones.rb +44 -0
- data/test/unit/test_translation.rb +27 -0
- data/test/unit/test_validations.rb +562 -0
- metadata +285 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class TimestampsTest < Test::Unit::TestCase
|
|
4
|
+
context "timestamping" do
|
|
5
|
+
setup do
|
|
6
|
+
@klass = Doc do
|
|
7
|
+
key :first_name, String
|
|
8
|
+
key :last_name, String
|
|
9
|
+
key :age, Integer
|
|
10
|
+
key :date, Date
|
|
11
|
+
end
|
|
12
|
+
@klass.timestamps!
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
should "set created_at and updated_at on create" do
|
|
16
|
+
doc = @klass.new(:first_name => 'John', :age => 27)
|
|
17
|
+
doc.created_at.should be(nil)
|
|
18
|
+
doc.updated_at.should be(nil)
|
|
19
|
+
doc.save
|
|
20
|
+
doc.created_at.should_not be(nil)
|
|
21
|
+
doc.updated_at.should_not be(nil)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
should "not overwrite created_at if it already exists" do
|
|
25
|
+
original_created_at = 1.month.ago
|
|
26
|
+
doc = @klass.new(:first_name => 'John', :age => 27, :created_at => original_created_at)
|
|
27
|
+
doc.created_at.to_i.should == original_created_at.to_i
|
|
28
|
+
doc.updated_at.should be_nil
|
|
29
|
+
doc.save
|
|
30
|
+
doc.created_at.to_i.should == original_created_at.to_i
|
|
31
|
+
doc.updated_at.should_not be_nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
should "set updated_at on field update but leave created_at alone" do
|
|
35
|
+
doc = @klass.create(:first_name => 'John', :age => 27)
|
|
36
|
+
old_created_at = doc.created_at
|
|
37
|
+
old_updated_at = doc.updated_at
|
|
38
|
+
doc.first_name = 'Johnny'
|
|
39
|
+
|
|
40
|
+
Timecop.freeze(Time.now + 5.seconds) do
|
|
41
|
+
doc.save
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
doc.created_at.should == old_created_at
|
|
45
|
+
doc.updated_at.should_not == old_updated_at
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
should "set updated_at on document update but leave created_at alone" do
|
|
49
|
+
doc = @klass.create(:first_name => 'John', :age => 27)
|
|
50
|
+
old_created_at = doc.created_at.to_f
|
|
51
|
+
|
|
52
|
+
new_updated_at = Time.now + 5.seconds
|
|
53
|
+
Timecop.freeze(new_updated_at) do
|
|
54
|
+
@klass.update(doc._id, { :first_name => 'Johnny' })
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
doc = doc.reload
|
|
58
|
+
doc.created_at.to_f.should be_close(old_created_at, 0.001)
|
|
59
|
+
doc.updated_at.to_f.should be_close(new_updated_at.to_f, 0.001)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class TouchTest < Test::Unit::TestCase
|
|
4
|
+
context "touch" do
|
|
5
|
+
context "document" do
|
|
6
|
+
setup do
|
|
7
|
+
@document = Doc { timestamps! }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
should "update the updated_at timestamp" do
|
|
11
|
+
doc = @document.create
|
|
12
|
+
old_updated_at = doc.updated_at
|
|
13
|
+
|
|
14
|
+
Timecop.freeze(Time.now + 1.day) do
|
|
15
|
+
doc.touch
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
doc.reload
|
|
19
|
+
doc.updated_at.should_not == old_updated_at
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context "embedded document" do
|
|
24
|
+
should "update the updated_at timestamp" do
|
|
25
|
+
Doc = Doc("Document") { timestamps!}
|
|
26
|
+
Emdoc = EDoc("EmbeddedDocument") { timestamps! }
|
|
27
|
+
Doc.has_many :emdocs, :class => Emdoc
|
|
28
|
+
|
|
29
|
+
doc = Doc.create
|
|
30
|
+
emdoc = Emdoc.new
|
|
31
|
+
doc.emdocs << emdoc
|
|
32
|
+
doc.save
|
|
33
|
+
|
|
34
|
+
old_updated_at = emdoc.updated_at
|
|
35
|
+
document_old_updated_at = doc.updated_at
|
|
36
|
+
|
|
37
|
+
Timecop.freeze(Time.now + 1.day) do
|
|
38
|
+
emdoc.touch
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
doc.reload
|
|
42
|
+
emdoc.updated_at.should_not == old_updated_at
|
|
43
|
+
doc.updated_at.should_not == document_old_updated_at
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context "association" do
|
|
48
|
+
setup do
|
|
49
|
+
@post_class = Doc("Post") do
|
|
50
|
+
key :touched_at, DateTime
|
|
51
|
+
timestamps!
|
|
52
|
+
end
|
|
53
|
+
@comment_class = Doc("Comment") do
|
|
54
|
+
key :post_id, ObjectId
|
|
55
|
+
key :text, String
|
|
56
|
+
timestamps!
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
@post_class.many :comments, :class => @comment_class
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
should 'not be true by default' do
|
|
63
|
+
@comment_class.belongs_to :post, :class => @post_class
|
|
64
|
+
@comment_class.associations[:post].touch?.should_not be_true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
context 'touch the parent when true' do
|
|
68
|
+
setup do
|
|
69
|
+
@comment_class.belongs_to :post, :class => @post_class, :touch => true
|
|
70
|
+
@post = @post_class.create(:title => 'Hello, world!')
|
|
71
|
+
@comment = @post.comments.build
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
should "when the child is created" do
|
|
75
|
+
orig_updated_at = @post.updated_at
|
|
76
|
+
Timecop.freeze(Time.now + 1.day) do
|
|
77
|
+
@comment.save
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
@post.reload.updated_at.should_not == orig_updated_at
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
should "when the child is updated" do
|
|
84
|
+
@comment.save
|
|
85
|
+
old_updated_at = @post.updated_at
|
|
86
|
+
Timecop.freeze(Time.now + 2.day) do
|
|
87
|
+
@comment.update_attributes(:text => "Something")
|
|
88
|
+
end
|
|
89
|
+
@post.reload.updated_at.should_not == old_updated_at
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
should "when the child is touched" do
|
|
93
|
+
@comment.save
|
|
94
|
+
old_updated_at = @post.updated_at
|
|
95
|
+
Timecop.freeze(Time.now + 3.day) do
|
|
96
|
+
@comment.touch
|
|
97
|
+
end
|
|
98
|
+
@post.reload.updated_at.should_not == old_updated_at
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
context "when set to a symbol that is a key of parent" do
|
|
103
|
+
should "set that key on touch events" do
|
|
104
|
+
@comment_class.belongs_to :post, :class => @post_class, :touch => :touched_at
|
|
105
|
+
post = @post_class.create(:title => 'Hello, world!')
|
|
106
|
+
post.touched_at.should be_nil
|
|
107
|
+
|
|
108
|
+
comment = post.comments.build
|
|
109
|
+
comment.save
|
|
110
|
+
post.reload.touched_at.should_not be_nil
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
should 'not touch the parent when false' do
|
|
115
|
+
post = @post_class.create(:title => 'Hello, world!')
|
|
116
|
+
comment = post.comments.build
|
|
117
|
+
Timecop.freeze(Time.now + 1.day) do
|
|
118
|
+
comment.save
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
post.reload.updated_at.should == post.created_at
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class UserstampsTest < Test::Unit::TestCase
|
|
4
|
+
class AltUser
|
|
5
|
+
include MongoMapper::Document
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
context "userstamping" do
|
|
9
|
+
setup do
|
|
10
|
+
@document = Doc do
|
|
11
|
+
userstamps!
|
|
12
|
+
end
|
|
13
|
+
@document_alt_user = Doc do
|
|
14
|
+
userstamps! :class_name => 'AltUser'
|
|
15
|
+
end
|
|
16
|
+
@document_alt_user_class = Doc do
|
|
17
|
+
userstamps! :class => AltUser
|
|
18
|
+
end
|
|
19
|
+
@docs = [@document, @document_alt_user, @document_alt_user_class]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
should "add creator_id key" do
|
|
23
|
+
@docs.each{ |d| d.keys.should include('creator_id') }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
should "add updater_id key" do
|
|
27
|
+
@docs.each{ |d| d.keys.should include('updater_id') }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
should "add belongs_to creator" do
|
|
31
|
+
@docs.each{ |d| d.associations.keys.should include(:creator) }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
should "add belongs_to updater" do
|
|
35
|
+
@docs.each{ |d| d.associations.keys.should include(:updater) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
should "properly set class names" do
|
|
39
|
+
@document.associations[:creator].class_name.should == 'User'
|
|
40
|
+
@document_alt_user.associations[:creator].class_name.should == 'AltUser'
|
|
41
|
+
@document_alt_user_class.associations[:creator].class_name.should == 'UserstampsTest::AltUser'
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class ValidationsTest < Test::Unit::TestCase
|
|
4
|
+
context "Saving a new document that is invalid" do
|
|
5
|
+
setup do
|
|
6
|
+
@document = Doc do
|
|
7
|
+
key :name, String, :required => true
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
should "not insert document" do
|
|
12
|
+
doc = @document.new
|
|
13
|
+
doc.save
|
|
14
|
+
@document.count.should == 0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
should "populate document's errors" do
|
|
18
|
+
doc = @document.new
|
|
19
|
+
doc.errors.size.should == 0
|
|
20
|
+
doc.save
|
|
21
|
+
doc.errors.full_messages.should == ["Name can't be blank"]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context "Saving a document that is invalid (destructive)" do
|
|
26
|
+
setup do
|
|
27
|
+
@document = Doc do
|
|
28
|
+
key :name, String, :required => true
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
should "raise error" do
|
|
33
|
+
doc = @document.new
|
|
34
|
+
lambda { doc.save! }.should raise_error(MongoMapper::DocumentNotValid)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
should "set document on exception" do
|
|
38
|
+
doc = @document.new
|
|
39
|
+
begin
|
|
40
|
+
doc.save!
|
|
41
|
+
rescue MongoMapper::DocumentNotValid => e
|
|
42
|
+
e.document.should == doc
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context "Creating a document that is invalid (destructive)" do
|
|
48
|
+
setup do
|
|
49
|
+
@document = Doc do
|
|
50
|
+
key :name, String, :required => true
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
should "raise error" do
|
|
55
|
+
lambda { @document.create! }.should raise_error(MongoMapper::DocumentNotValid)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
should "create a new document" do
|
|
59
|
+
instance = @document.create!(:name => "James")
|
|
60
|
+
instance.new_record?.should be_false
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context "Saving an existing document that is invalid" do
|
|
65
|
+
setup do
|
|
66
|
+
@document = Doc do
|
|
67
|
+
key :name, String, :required => true
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
@doc = @document.create(:name => 'John Nunemaker')
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
should "not update document" do
|
|
74
|
+
@doc.name = nil
|
|
75
|
+
@doc.save
|
|
76
|
+
@doc.reload.name.should == 'John Nunemaker'
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
should "populate document's errors" do
|
|
80
|
+
@doc.name = nil
|
|
81
|
+
@doc.save
|
|
82
|
+
@doc.errors.full_messages.should == ["Name can't be blank"]
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
context "Adding validation errors" do
|
|
87
|
+
setup do
|
|
88
|
+
@document = Doc do
|
|
89
|
+
key :action, String
|
|
90
|
+
def action_present
|
|
91
|
+
errors.add(:action, 'is invalid') if action.blank?
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
should "work with validate :on => :create callback" do
|
|
97
|
+
@document.validate :action_present, :on => :create
|
|
98
|
+
|
|
99
|
+
doc = @document.create(:action => nil)
|
|
100
|
+
doc.should have_error_on(:action)
|
|
101
|
+
|
|
102
|
+
doc.action = 'kick'
|
|
103
|
+
doc.save
|
|
104
|
+
doc.should_not have_error_on(:action)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
should "work with validate :on => :update callback" do
|
|
108
|
+
@document.validate :action_present, :on => :update
|
|
109
|
+
|
|
110
|
+
doc = @document.new
|
|
111
|
+
doc.action = nil
|
|
112
|
+
doc.should_not have_error_on(:action)
|
|
113
|
+
doc.save
|
|
114
|
+
|
|
115
|
+
doc.action = nil
|
|
116
|
+
doc.should have_error_on(:action)
|
|
117
|
+
|
|
118
|
+
doc.action = 'kick'
|
|
119
|
+
doc.should_not have_error_on(:action)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
context "validating uniqueness of" do
|
|
124
|
+
setup do
|
|
125
|
+
@document = Doc do
|
|
126
|
+
key :name, String
|
|
127
|
+
validates_uniqueness_of :name
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
should "not fail if object is new" do
|
|
132
|
+
doc = @document.new
|
|
133
|
+
doc.should_not have_error_on(:name)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
should "not fail when new object is out of scope" do
|
|
137
|
+
document = Doc do
|
|
138
|
+
key :name
|
|
139
|
+
key :adult
|
|
140
|
+
validates_uniqueness_of :name, :scope => :adult
|
|
141
|
+
end
|
|
142
|
+
doc = document.new("name" => "joe", :adult => true)
|
|
143
|
+
doc.save.should be_true
|
|
144
|
+
|
|
145
|
+
doc2 = document.new("name" => "joe", :adult => false)
|
|
146
|
+
doc2.should be_valid
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
should "work with i18n taken message" do
|
|
150
|
+
@document.create(:name => 'joe')
|
|
151
|
+
doc = @document.create(:name => 'joe')
|
|
152
|
+
doc.should have_error_on(:name, 'has already been taken')
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
should "allow to update an object" do
|
|
156
|
+
doc = @document.new("name" => "joe")
|
|
157
|
+
doc.save.should be_true
|
|
158
|
+
|
|
159
|
+
@document \
|
|
160
|
+
.stubs(:first) \
|
|
161
|
+
.with(:name => 'joe') \
|
|
162
|
+
.returns(doc)
|
|
163
|
+
|
|
164
|
+
doc.name = "joe"
|
|
165
|
+
doc.valid?.should be_true
|
|
166
|
+
doc.should_not have_error_on(:name)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
should "fail if object name is not unique" do
|
|
170
|
+
doc = @document.new("name" => "joe")
|
|
171
|
+
doc.save.should be_true
|
|
172
|
+
|
|
173
|
+
@document \
|
|
174
|
+
.stubs(:first) \
|
|
175
|
+
.with(:name => 'joe') \
|
|
176
|
+
.returns(doc)
|
|
177
|
+
|
|
178
|
+
doc2 = @document.new("name" => "joe")
|
|
179
|
+
doc2.should have_error_on(:name)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
should "allow multiple blank entries if :allow_blank => true" do
|
|
183
|
+
document = Doc do
|
|
184
|
+
key :name
|
|
185
|
+
validates_uniqueness_of :name, :allow_blank => :true
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
doc = document.new("name" => "")
|
|
189
|
+
doc.save.should be_true
|
|
190
|
+
|
|
191
|
+
document \
|
|
192
|
+
.stubs(:first) \
|
|
193
|
+
.with(:name => '') \
|
|
194
|
+
.returns(doc)
|
|
195
|
+
|
|
196
|
+
doc2 = document.new("name" => "")
|
|
197
|
+
doc2.should_not have_error_on(:name)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
should "allow multiple nil entries if :allow_nil => true" do
|
|
201
|
+
document = Doc do
|
|
202
|
+
key :name
|
|
203
|
+
validates_uniqueness_of :name, :allow_nil => :true
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
doc = document.new('name' => nil)
|
|
207
|
+
doc.save.should be_true
|
|
208
|
+
|
|
209
|
+
doc2 = document.new('name' => nil)
|
|
210
|
+
doc2.should_not have_error_on(:name)
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
should "allow entries that differ only in case by default" do
|
|
214
|
+
document = Doc do
|
|
215
|
+
key :name
|
|
216
|
+
validates_uniqueness_of :name
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
doc = document.new("name" => "BLAMMO")
|
|
220
|
+
doc.save.should be_true
|
|
221
|
+
|
|
222
|
+
doc2 = document.new("name" => "blammo")
|
|
223
|
+
doc2.should_not have_error_on(:name)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
context "with :case_sensitive => false" do
|
|
227
|
+
setup do
|
|
228
|
+
@document = Doc do
|
|
229
|
+
key :name
|
|
230
|
+
validates_uniqueness_of :name, :case_sensitive => false
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
should "fail on entries that differ only in case" do
|
|
235
|
+
doc = @document.new("name" => "BLAMMO")
|
|
236
|
+
doc.save.should be_true
|
|
237
|
+
|
|
238
|
+
doc2 = @document.new("name" => "blammo")
|
|
239
|
+
doc2.should have_error_on(:name)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
should "not raise an error if value is nil" do
|
|
243
|
+
doc = @document.new("name" => nil)
|
|
244
|
+
lambda { doc.valid? }.should_not raise_error
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
should "not raise an error if special Regexp characters used" do
|
|
248
|
+
doc = @document.new("name" => '?')
|
|
249
|
+
lambda { doc.valid? }.should_not raise_error
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
should "check for uniqueness using entire string" do
|
|
253
|
+
doc = @document.new("name" => "John Doe")
|
|
254
|
+
doc.save.should be_true
|
|
255
|
+
|
|
256
|
+
doc2 = @document.new("name" => "John")
|
|
257
|
+
doc2.valid?.should be_true
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
context "scoped by a single attribute" do
|
|
262
|
+
setup do
|
|
263
|
+
@document = Doc do
|
|
264
|
+
key :name, String
|
|
265
|
+
key :scope, String
|
|
266
|
+
validates_uniqueness_of :name, :scope => :scope
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
should "fail if the same name exists in the scope" do
|
|
271
|
+
doc = @document.new("name" => "joe", "scope" => "one")
|
|
272
|
+
doc.save.should be_true
|
|
273
|
+
|
|
274
|
+
@document \
|
|
275
|
+
.stubs(:first) \
|
|
276
|
+
.with(:name => 'joe', :scope => "one") \
|
|
277
|
+
.returns(doc)
|
|
278
|
+
|
|
279
|
+
doc2 = @document.new("name" => "joe", "scope" => "one")
|
|
280
|
+
doc2.should have_error_on(:name)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
should "pass if the same name exists in a different scope" do
|
|
284
|
+
doc = @document.new("name" => "joe", "scope" => "one")
|
|
285
|
+
doc.save.should be_true
|
|
286
|
+
|
|
287
|
+
@document \
|
|
288
|
+
.stubs(:first) \
|
|
289
|
+
.with(:name => 'joe', :scope => 'two') \
|
|
290
|
+
.returns(nil)
|
|
291
|
+
|
|
292
|
+
doc2 = @document.new("name" => "joe", "scope" => "two")
|
|
293
|
+
doc2.should_not have_error_on(:name)
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
context "scoped by a multiple attributes" do
|
|
298
|
+
setup do
|
|
299
|
+
@document = Doc do
|
|
300
|
+
key :name, String
|
|
301
|
+
key :first_scope, String
|
|
302
|
+
key :second_scope, String
|
|
303
|
+
validates_uniqueness_of :name, :scope => [:first_scope, :second_scope]
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
should "fail if the same name exists in the scope" do
|
|
308
|
+
doc = @document.new("name" => "joe", "first_scope" => "one", "second_scope" => "two")
|
|
309
|
+
doc.save.should be_true
|
|
310
|
+
|
|
311
|
+
@document \
|
|
312
|
+
.stubs(:first) \
|
|
313
|
+
.with(:name => 'joe', :first_scope => 'one', :second_scope => 'two') \
|
|
314
|
+
.returns(doc)
|
|
315
|
+
|
|
316
|
+
doc2 = @document.new("name" => "joe", "first_scope" => "one", "second_scope" => "two")
|
|
317
|
+
doc2.should have_error_on(:name)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
should "pass if the same name exists in a different scope" do
|
|
321
|
+
doc = @document.new("name" => "joe", "first_scope" => "one", "second_scope" => "two")
|
|
322
|
+
doc.save.should be_true
|
|
323
|
+
|
|
324
|
+
@document \
|
|
325
|
+
.stubs(:first) \
|
|
326
|
+
.with(:name => 'joe', :first_scope => 'one', :second_scope => 'one') \
|
|
327
|
+
.returns(nil)
|
|
328
|
+
|
|
329
|
+
doc2 = @document.new("name" => "joe", "first_scope" => "one", "second_scope" => "one")
|
|
330
|
+
doc2.should_not have_error_on(:name)
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
context "validating associated docs" do
|
|
336
|
+
setup do
|
|
337
|
+
@child_class = EDoc do
|
|
338
|
+
key :name, :required => true
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
@root_class = Doc { }
|
|
342
|
+
@root_class.many :children, :class => @child_class
|
|
343
|
+
@root_class.validates_associated :children, :message => 'are invalid'
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
should "pass if there are no associated docs" do
|
|
347
|
+
doc = @root_class.new
|
|
348
|
+
doc.save.should be_true
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
should "pass if the associated doc is valid" do
|
|
352
|
+
doc = @root_class.new
|
|
353
|
+
doc.children.build(:name => 'Joe')
|
|
354
|
+
doc.save.should be_true
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
should "fail if the associated doc is invalid" do
|
|
358
|
+
doc = @root_class.new
|
|
359
|
+
doc.children.build
|
|
360
|
+
doc.should have_error_on(:children, 'are invalid')
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
context "validating associated docs with custom context" do
|
|
366
|
+
setup do
|
|
367
|
+
@child_class = EDoc do
|
|
368
|
+
key :name
|
|
369
|
+
|
|
370
|
+
validates_length_of :name, :minimum => 5, :on => :custom_context
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
@root_class = Doc { }
|
|
374
|
+
@root_class.many :children, :class => @child_class
|
|
375
|
+
@root_class.validates_associated :children, :context => :custom_context
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
should "pass if there are no associated docs" do
|
|
379
|
+
doc = @root_class.new
|
|
380
|
+
doc.valid?(:custom_context).should be_true
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
should "pass if the associated doc is valid" do
|
|
384
|
+
doc = @root_class.new
|
|
385
|
+
doc.children.build(:name => 'George')
|
|
386
|
+
doc.valid?(:custom_context).should be_true
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
should "fail if the associated doc is invalid" do
|
|
390
|
+
doc = @root_class.new
|
|
391
|
+
doc.children.build(:name => 'Bob')
|
|
392
|
+
doc.valid?(:custom_context).should_not be_true
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
end
|
|
396
|
+
# context "validates uniqueness of with :unique shortcut" do
|
|
397
|
+
# should "work" do
|
|
398
|
+
# @document = Doc do
|
|
399
|
+
# key :name, String, :unique => true
|
|
400
|
+
# end
|
|
401
|
+
#
|
|
402
|
+
# doc = @document.create(:name => 'John')
|
|
403
|
+
# doc.should_not have_error_on(:name)
|
|
404
|
+
#
|
|
405
|
+
# @document \
|
|
406
|
+
# .stubs(:first) \
|
|
407
|
+
# .with(:name => 'John') \
|
|
408
|
+
# .returns(doc)
|
|
409
|
+
#
|
|
410
|
+
# second_john = @document.create(:name => 'John')
|
|
411
|
+
# second_john.should have_error_on(:name, 'has already been taken')
|
|
412
|
+
# end
|
|
413
|
+
# end
|
|
414
|
+
end
|