jmonteiro-mongo_mapper 0.1.0

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.
Files changed (91) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +38 -0
  4. data/Rakefile +55 -0
  5. data/VERSION +1 -0
  6. data/bin/mmconsole +60 -0
  7. data/jmonteiro-mongo_mapper.gemspec +195 -0
  8. data/lib/mongo_mapper.rb +128 -0
  9. data/lib/mongo_mapper/descendant_appends.rb +44 -0
  10. data/lib/mongo_mapper/document.rb +402 -0
  11. data/lib/mongo_mapper/dynamic_finder.rb +74 -0
  12. data/lib/mongo_mapper/embedded_document.rb +61 -0
  13. data/lib/mongo_mapper/finder_options.rb +127 -0
  14. data/lib/mongo_mapper/plugins.rb +19 -0
  15. data/lib/mongo_mapper/plugins/associations.rb +104 -0
  16. data/lib/mongo_mapper/plugins/associations/base.rb +121 -0
  17. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +28 -0
  18. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +23 -0
  19. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  20. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +49 -0
  21. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  22. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  23. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  24. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  25. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  26. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  27. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +66 -0
  28. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  29. data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
  30. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  31. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  32. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  33. data/lib/mongo_mapper/plugins/equality.rb +11 -0
  34. data/lib/mongo_mapper/plugins/identity_map.rb +66 -0
  35. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  36. data/lib/mongo_mapper/plugins/keys.rb +295 -0
  37. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  38. data/lib/mongo_mapper/plugins/pagination.rb +85 -0
  39. data/lib/mongo_mapper/plugins/protected.rb +31 -0
  40. data/lib/mongo_mapper/plugins/rails.rb +80 -0
  41. data/lib/mongo_mapper/plugins/serialization.rb +109 -0
  42. data/lib/mongo_mapper/plugins/validations.rb +48 -0
  43. data/lib/mongo_mapper/support.rb +213 -0
  44. data/performance/read_write.rb +52 -0
  45. data/specs.watchr +51 -0
  46. data/test/NOTE_ON_TESTING +1 -0
  47. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  48. data/test/functional/associations/test_belongs_to_proxy.rb +93 -0
  49. data/test/functional/associations/test_in_array_proxy.rb +309 -0
  50. data/test/functional/associations/test_many_documents_as_proxy.rb +246 -0
  51. data/test/functional/associations/test_many_documents_proxy.rb +437 -0
  52. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +175 -0
  53. data/test/functional/associations/test_many_embedded_proxy.rb +216 -0
  54. data/test/functional/associations/test_many_polymorphic_proxy.rb +340 -0
  55. data/test/functional/associations/test_one_proxy.rb +149 -0
  56. data/test/functional/test_associations.rb +44 -0
  57. data/test/functional/test_binary.rb +27 -0
  58. data/test/functional/test_callbacks.rb +81 -0
  59. data/test/functional/test_dirty.rb +156 -0
  60. data/test/functional/test_document.rb +1171 -0
  61. data/test/functional/test_embedded_document.rb +125 -0
  62. data/test/functional/test_identity_map.rb +233 -0
  63. data/test/functional/test_logger.rb +20 -0
  64. data/test/functional/test_modifiers.rb +252 -0
  65. data/test/functional/test_pagination.rb +93 -0
  66. data/test/functional/test_protected.rb +41 -0
  67. data/test/functional/test_string_id_compatibility.rb +67 -0
  68. data/test/functional/test_validations.rb +329 -0
  69. data/test/models.rb +232 -0
  70. data/test/support/custom_matchers.rb +55 -0
  71. data/test/support/timing.rb +16 -0
  72. data/test/test_helper.rb +60 -0
  73. data/test/unit/associations/test_base.rb +207 -0
  74. data/test/unit/associations/test_proxy.rb +103 -0
  75. data/test/unit/serializers/test_json_serializer.rb +189 -0
  76. data/test/unit/test_descendant_appends.rb +71 -0
  77. data/test/unit/test_document.rb +203 -0
  78. data/test/unit/test_dynamic_finder.rb +125 -0
  79. data/test/unit/test_embedded_document.rb +628 -0
  80. data/test/unit/test_finder_options.rb +325 -0
  81. data/test/unit/test_keys.rb +169 -0
  82. data/test/unit/test_mongo_mapper.rb +65 -0
  83. data/test/unit/test_pagination.rb +127 -0
  84. data/test/unit/test_plugins.rb +42 -0
  85. data/test/unit/test_rails.rb +139 -0
  86. data/test/unit/test_rails_compatibility.rb +42 -0
  87. data/test/unit/test_serialization.rb +51 -0
  88. data/test/unit/test_support.rb +350 -0
  89. data/test/unit/test_time_zones.rb +39 -0
  90. data/test/unit/test_validations.rb +492 -0
  91. metadata +260 -0
@@ -0,0 +1,149 @@
1
+ require 'test_helper'
2
+
3
+ class OneProxyTest < Test::Unit::TestCase
4
+ def setup
5
+ @post_class = Doc('Post')
6
+ @author_class = Doc do
7
+ key :post_id, ObjectId
8
+ end
9
+ end
10
+
11
+ should "default to nil" do
12
+ @post_class.one :author, :class => @author_class
13
+ @post_class.new.author.nil?.should be_true
14
+ end
15
+
16
+ should "be able to replace the association" do
17
+ @post_class.one :author, :class => @author_class
18
+
19
+ post = @post_class.new
20
+ author = @author_class.new(:name => 'Frank')
21
+ post.author = author
22
+ post.reload
23
+
24
+ post.author.should == author
25
+ post.author.nil?.should be_false
26
+
27
+ new_author = @author_class.new(:name => 'Emily')
28
+ post.author = new_author
29
+ post.author.should == new_author
30
+ end
31
+
32
+ should "have boolean method for testing presence" do
33
+ @post_class.one :author, :class => @author_class
34
+
35
+ post = @post_class.new
36
+ post.author?.should be_false
37
+
38
+ post.author = @author_class.new(:name => 'Frank')
39
+ post.author?.should be_true
40
+ end
41
+
42
+ should "work with criteria" do
43
+ @post_class.one :primary_author, :class => @author_class, :primary => true
44
+ @post_class.one :author, :class => @author_class
45
+
46
+ post = @post_class.create
47
+ author = @author_class.create(:name => 'Frank', :primary => false, :post_id => post.id)
48
+ primary = @author_class.create(:name => 'Bill', :primary => true, :post_id => post.id)
49
+ post.author.should == author
50
+ post.primary_author.should == primary
51
+ end
52
+
53
+ should "unset the association" do
54
+ @post_class.one :author, :class => @author_class
55
+ post = @post_class.new
56
+ author = @author_class.new
57
+ post.author = author
58
+ post.reload
59
+
60
+ post.author = nil
61
+ post.author.nil?.should be_false
62
+ end
63
+
64
+ should "work with :dependent delete" do
65
+ @post_class.one :author, :class => @author_class, :dependent => :delete
66
+
67
+ post = @post_class.create
68
+ author = @author_class.new
69
+ post.author = author
70
+ post.reload
71
+
72
+ @author_class.any_instance.expects(:delete).once
73
+ post.author = @author_class.new
74
+ end
75
+
76
+ should "work with :dependent destroy" do
77
+ @post_class.one :author, :class => @author_class, :dependent => :destroy
78
+
79
+ post = @post_class.create
80
+ author = @author_class.new
81
+ post.author = author
82
+ post.reload
83
+
84
+ @author_class.any_instance.expects(:destroy).once
85
+ post.author = @author_class.new
86
+ end
87
+
88
+ should "work with :dependent nullify" do
89
+ @post_class.one :author, :class => @author_class, :dependent => :nullify
90
+
91
+ post = @post_class.create
92
+ author = @author_class.new
93
+ post.author = author
94
+ post.reload
95
+
96
+ post.author = @author_class.new
97
+
98
+ author.reload
99
+ author.post_id.should be_nil
100
+ end
101
+
102
+ should "be able to build" do
103
+ @post_class.one :author, :class => @author_class
104
+
105
+ post = @post_class.create
106
+ author = post.author.build(:name => 'John')
107
+ post.author.should be_instance_of(@author_class)
108
+ post.author.should be_new
109
+ post.author.name.should == 'John'
110
+ post.author.should == author
111
+ post.author.post_id.should == post.id
112
+ end
113
+
114
+ should "be able to create" do
115
+ @post_class.one :author, :class => @author_class
116
+
117
+ post = @post_class.create
118
+ author = post.author.create(:name => 'John')
119
+ post.author.should be_instance_of(@author_class)
120
+ post.author.should_not be_new
121
+ post.author.name.should == 'John'
122
+ post.author.should == author
123
+ post.author.post_id.should == post.id
124
+ end
125
+
126
+ context "#create!" do
127
+ setup do
128
+ @author_class.key :name, String, :required => true
129
+ @post_class.one :author, :class => @author_class
130
+ end
131
+
132
+ should "raise exception if invalid" do
133
+ post = @post_class.create
134
+ assert_raises(MongoMapper::DocumentNotValid) do
135
+ post.author.create!
136
+ end
137
+ end
138
+
139
+ should "work if valid" do
140
+ post = @post_class.create
141
+ author = post.author.create!(:name => 'John')
142
+ post.author.should be_instance_of(@author_class)
143
+ post.author.should_not be_new
144
+ post.author.name.should == 'John'
145
+ post.author.should == author
146
+ post.author.post_id.should == post.id
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,44 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class AssociationsTest < Test::Unit::TestCase
5
+ should "allow changing class names" do
6
+ class AwesomeUser
7
+ include MongoMapper::Document
8
+
9
+ many :posts, :class_name => 'AssociationsTest::AwesomePost', :foreign_key => :creator_id
10
+ end
11
+ AwesomeUser.collection.remove
12
+
13
+ class AwesomeTag
14
+ include MongoMapper::EmbeddedDocument
15
+
16
+ key :name, String
17
+ key :post_id, ObjectId
18
+
19
+ belongs_to :post, :class_name => 'AssociationsTest::AwesomeUser'
20
+ end
21
+
22
+ class AwesomePost
23
+ include MongoMapper::Document
24
+
25
+ key :creator_id, ObjectId
26
+
27
+ belongs_to :creator, :class_name => 'AssociationsTest::AwesomeUser'
28
+ many :tags, :class_name => 'AssociationsTest::AwesomeTag', :foreign_key => :post_id
29
+ end
30
+
31
+ AwesomeUser.collection.remove
32
+ AwesomePost.collection.remove
33
+
34
+ user = AwesomeUser.create
35
+ tag1 = AwesomeTag.new(:name => 'awesome')
36
+ tag2 = AwesomeTag.new(:name => 'grand')
37
+ post1 = AwesomePost.create(:creator => user, :tags => [tag1])
38
+ post2 = AwesomePost.create(:creator => user, :tags => [tag2])
39
+ user.posts.should == [post1, post2]
40
+
41
+ post1 = post1.reload
42
+ post1.tags.should == [tag1]
43
+ end
44
+ end
@@ -0,0 +1,27 @@
1
+ require 'test_helper'
2
+
3
+ class BinaryTest < Test::Unit::TestCase
4
+ should "serialize and deserialize correctly" do
5
+ klass = Doc do
6
+ key :contents, Binary
7
+ end
8
+
9
+ doc = klass.new(:contents => '010101')
10
+ doc.save
11
+
12
+ doc = doc.reload
13
+ doc.contents.to_s.should == ByteBuffer.new('010101').to_s
14
+ end
15
+
16
+ context "Saving a document with a blank binary value" do
17
+ setup do
18
+ @document = Doc do
19
+ key :file, Binary
20
+ end
21
+ end
22
+
23
+ should "not fail" do
24
+ assert_nothing_raised { @document.new(:file => nil).save }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,81 @@
1
+ require 'test_helper'
2
+
3
+ class CallbacksTest < Test::Unit::TestCase
4
+ context "Defining and running callbacks" do
5
+ setup do
6
+ @document = Doc do
7
+ key :name, String
8
+
9
+ [ :before_validation_on_create, :before_validation_on_update,
10
+ :before_validation, :after_validation,
11
+ :before_create, :after_create,
12
+ :before_update, :after_update,
13
+ :before_save, :after_save,
14
+ :before_destroy, :after_destroy].each do |callback|
15
+ callback_method = "#{callback}_callback"
16
+ send(callback, callback_method)
17
+ define_method(callback_method) do
18
+ history << callback.to_sym
19
+ end
20
+ end
21
+
22
+ def history
23
+ @history ||= []
24
+ end
25
+
26
+ def clear_history
27
+ @history = nil
28
+ end
29
+ end
30
+ end
31
+
32
+ should "get the order right for creating documents" do
33
+ doc = @document.create(:name => 'John Nunemaker')
34
+ doc.history.should == [:before_validation, :before_validation_on_create, :after_validation, :before_save, :before_create, :after_create, :after_save]
35
+ end
36
+
37
+ should "get the order right for updating documents" do
38
+ doc = @document.create(:name => 'John Nunemaker')
39
+ doc.clear_history
40
+ doc.name = 'John'
41
+ doc.save
42
+ doc.history.should == [:before_validation, :before_validation_on_update, :after_validation, :before_save, :before_update, :after_update, :after_save]
43
+ end
44
+
45
+ should "work for before and after validation" do
46
+ doc = @document.new(:name => 'John Nunemaker')
47
+ doc.valid?
48
+ doc.history.should include(:before_validation)
49
+ doc.history.should include(:after_validation)
50
+ end
51
+
52
+ should "work for before and after create" do
53
+ doc = @document.create(:name => 'John Nunemaker')
54
+ doc.history.should include(:before_create)
55
+ doc.history.should include(:after_create)
56
+ end
57
+
58
+ should "work for before and after update" do
59
+ doc = @document.create(:name => 'John Nunemaker')
60
+ doc.name = 'John Doe'
61
+ doc.save
62
+ doc.history.should include(:before_update)
63
+ doc.history.should include(:after_update)
64
+ end
65
+
66
+ should "work for before and after save" do
67
+ doc = @document.new
68
+ doc.name = 'John Doe'
69
+ doc.save
70
+ doc.history.should include(:before_save)
71
+ doc.history.should include(:after_save)
72
+ end
73
+
74
+ should "work for before and after destroy" do
75
+ doc = @document.create(:name => 'John Nunemaker')
76
+ doc.destroy
77
+ doc.history.should include(:before_destroy)
78
+ doc.history.should include(:after_destroy)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,156 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class DirtyTest < Test::Unit::TestCase
5
+ def setup
6
+ @document = Doc do
7
+ key :phrase, String
8
+ end
9
+
10
+ Status.collection.remove
11
+ Project.collection.remove
12
+ end
13
+
14
+ context "marking changes" do
15
+ should "not happen if there are none" do
16
+ doc = @document.new
17
+ doc.phrase_changed?.should be_false
18
+ doc.phrase_change.should be_nil
19
+ end
20
+
21
+ should "happen when change happens" do
22
+ doc = @document.new
23
+ doc.phrase = 'Golly Gee Willikers Batman'
24
+ doc.phrase_changed?.should be_true
25
+ doc.phrase_was.should be_nil
26
+ doc.phrase_change.should == [nil, 'Golly Gee Willikers Batman']
27
+ end
28
+
29
+ should "happen when initializing" do
30
+ doc = @document.new(:phrase => 'Foo')
31
+ doc.changed?.should be_true
32
+ end
33
+
34
+ should "clear changes on save" do
35
+ doc = @document.new
36
+ doc.phrase = 'Golly Gee Willikers Batman'
37
+ doc.phrase_changed?.should be_true
38
+ doc.save
39
+ doc.phrase_changed?.should_not be_true
40
+ doc.phrase_change.should be_nil
41
+ end
42
+
43
+ should "clear changes on save!" do
44
+ doc = @document.new
45
+ doc.phrase = 'Golly Gee Willikers Batman'
46
+ doc.phrase_changed?.should be_true
47
+ doc.save!
48
+ doc.phrase_changed?.should_not be_true
49
+ doc.phrase_change.should be_nil
50
+ end
51
+
52
+ should "not happen when loading from database" do
53
+ doc = @document.create(:phrase => 'Foo')
54
+ doc.phrase = 'Fart'
55
+ doc.changed?.should be_true
56
+ doc.reload
57
+ doc.changed?.should be_false
58
+ end
59
+
60
+ should "happen if changed after loading from database" do
61
+ doc = @document.create(:phrase => 'Foo')
62
+ doc.reload
63
+ doc.changed?.should be_false
64
+ doc.phrase = 'Bar'
65
+ doc.changed?.should be_true
66
+ end
67
+ end
68
+
69
+ context "blank new value and type integer" do
70
+ should "not mark changes" do
71
+ @document.key :age, Integer
72
+
73
+ [nil, ''].each do |value|
74
+ doc = @document.new
75
+ doc.age = value
76
+ doc.age_changed?.should be_false
77
+ doc.age_change.should be_nil
78
+ end
79
+ end
80
+ end
81
+
82
+ context "blank new value and type float" do
83
+ should "not mark changes" do
84
+ @document.key :amount, Float
85
+
86
+ [nil, ''].each do |value|
87
+ doc = @document.new
88
+ doc.amount = value
89
+ doc.amount_changed?.should be_false
90
+ doc.amount_change.should be_nil
91
+ end
92
+ end
93
+ end
94
+
95
+ context "changed?" do
96
+ should "be true if key changed" do
97
+ doc = @document.new
98
+ doc.phrase = 'A penny saved is a penny earned.'
99
+ doc.changed?.should be_true
100
+ end
101
+
102
+ should "be false if no keys changed" do
103
+ @document.new.changed?.should be_false
104
+ end
105
+ end
106
+
107
+ context "changes" do
108
+ should "be empty hash if no changes" do
109
+ @document.new.changes.should == {}
110
+ end
111
+
112
+ should "be hash of keys with values of changes if there are changes" do
113
+ doc = @document.new
114
+ doc.phrase = 'A penny saved is a penny earned.'
115
+ doc.changes['phrase'].should == [nil, 'A penny saved is a penny earned.']
116
+ end
117
+ end
118
+
119
+ context "changed" do
120
+ should "be empty array if no changes" do
121
+ @document.new.changed.should == []
122
+ end
123
+
124
+ should "be array of keys that have changed if there are changes" do
125
+ doc = @document.new
126
+ doc.phrase = 'A penny saved is a penny earned.'
127
+ doc.changed.should == ['phrase']
128
+ end
129
+ end
130
+
131
+ context "will_change!" do
132
+ should "mark changes" do
133
+ doc = @document.create(:phrase => 'Foo')
134
+
135
+ doc.phrase << 'bar'
136
+ doc.phrase_changed?.should be_false
137
+
138
+ doc.phrase_will_change!
139
+ doc.phrase_changed?.should be_true
140
+ doc.phrase_change.should == ['Foobar', 'Foobar']
141
+
142
+ doc.phrase << '!'
143
+ doc.phrase_changed?.should be_true
144
+ doc.phrase_change.should == ['Foobar', 'Foobar!']
145
+ end
146
+ end
147
+
148
+ context "changing a foreign key through association" do
149
+ should "mark changes" do
150
+ status = Status.create(:name => 'Foo')
151
+ status.project = Project.create(:name => 'Bar')
152
+ status.changed?.should be_true
153
+ status.changed.should == %w(project_id)
154
+ end
155
+ end
156
+ end