mongo_mapper 0.6.10 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/README.rdoc +5 -14
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/lib/mongo_mapper.rb +48 -56
  5. data/lib/mongo_mapper/document.rb +136 -164
  6. data/lib/mongo_mapper/embedded_document.rb +29 -354
  7. data/lib/mongo_mapper/plugins.rb +31 -0
  8. data/lib/mongo_mapper/plugins/associations.rb +105 -0
  9. data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
  10. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  11. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  12. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  13. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +50 -0
  14. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  15. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  16. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  17. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  18. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  19. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  20. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  21. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  22. data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
  23. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  24. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  25. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  26. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  27. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  28. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  29. data/lib/mongo_mapper/plugins/keys.rb +324 -0
  30. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  31. data/lib/mongo_mapper/plugins/pagination.rb +24 -0
  32. data/lib/mongo_mapper/plugins/pagination/proxy.rb +68 -0
  33. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  34. data/lib/mongo_mapper/plugins/rails.rb +45 -0
  35. data/lib/mongo_mapper/plugins/serialization.rb +105 -0
  36. data/lib/mongo_mapper/plugins/validations.rb +46 -0
  37. data/lib/mongo_mapper/query.rb +130 -0
  38. data/lib/mongo_mapper/support.rb +40 -17
  39. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  40. data/lib/mongo_mapper/support/find.rb +77 -0
  41. data/mongo_mapper.gemspec +55 -38
  42. data/performance/read_write.rb +52 -0
  43. data/specs.watchr +23 -2
  44. data/test/functional/associations/test_belongs_to_proxy.rb +12 -10
  45. data/test/functional/associations/test_many_documents_as_proxy.rb +4 -21
  46. data/test/functional/associations/test_many_documents_proxy.rb +2 -8
  47. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +59 -39
  48. data/test/functional/associations/test_many_embedded_proxy.rb +145 -81
  49. data/test/functional/associations/test_many_polymorphic_proxy.rb +2 -40
  50. data/test/functional/associations/test_one_proxy.rb +25 -10
  51. data/test/functional/test_binary.rb +2 -8
  52. data/test/functional/test_callbacks.rb +1 -5
  53. data/test/functional/test_dirty.rb +27 -23
  54. data/test/functional/test_document.rb +224 -165
  55. data/test/functional/test_embedded_document.rb +72 -82
  56. data/test/functional/test_identity_map.rb +508 -0
  57. data/test/functional/test_modifiers.rb +15 -5
  58. data/test/functional/test_pagination.rb +1 -3
  59. data/test/functional/test_protected.rb +155 -0
  60. data/test/functional/test_string_id_compatibility.rb +7 -12
  61. data/test/functional/test_validations.rb +26 -58
  62. data/test/models.rb +0 -39
  63. data/test/test_helper.rb +37 -3
  64. data/test/unit/associations/test_base.rb +5 -5
  65. data/test/unit/associations/test_proxy.rb +8 -6
  66. data/test/unit/test_descendant_appends.rb +71 -0
  67. data/test/unit/test_document.rb +71 -76
  68. data/test/unit/test_dynamic_finder.rb +27 -29
  69. data/test/unit/test_embedded_document.rb +555 -601
  70. data/test/unit/{test_key.rb → test_keys.rb} +2 -5
  71. data/test/unit/test_mongo_mapper.rb +69 -9
  72. data/test/unit/test_pagination.rb +40 -32
  73. data/test/unit/test_plugins.rb +50 -0
  74. data/test/unit/{test_finder_options.rb → test_query.rb} +74 -65
  75. data/test/unit/test_rails.rb +123 -0
  76. data/test/unit/{test_serializations.rb → test_serialization.rb} +1 -2
  77. data/test/unit/test_support.rb +23 -7
  78. data/test/unit/test_time_zones.rb +3 -4
  79. data/test/unit/test_validations.rb +58 -17
  80. metadata +53 -36
  81. data/lib/mongo_mapper/associations.rb +0 -78
  82. data/lib/mongo_mapper/associations/base.rb +0 -119
  83. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +0 -26
  84. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +0 -21
  85. data/lib/mongo_mapper/associations/collection.rb +0 -19
  86. data/lib/mongo_mapper/associations/in_array_proxy.rb +0 -137
  87. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -26
  88. data/lib/mongo_mapper/associations/many_documents_proxy.rb +0 -115
  89. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +0 -31
  90. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +0 -54
  91. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +0 -11
  92. data/lib/mongo_mapper/associations/one_proxy.rb +0 -64
  93. data/lib/mongo_mapper/associations/proxy.rb +0 -116
  94. data/lib/mongo_mapper/callbacks.rb +0 -61
  95. data/lib/mongo_mapper/dirty.rb +0 -117
  96. data/lib/mongo_mapper/dynamic_finder.rb +0 -74
  97. data/lib/mongo_mapper/finder_options.rb +0 -145
  98. data/lib/mongo_mapper/key.rb +0 -36
  99. data/lib/mongo_mapper/mongo_mapper.rb +0 -125
  100. data/lib/mongo_mapper/pagination.rb +0 -66
  101. data/lib/mongo_mapper/rails_compatibility/document.rb +0 -15
  102. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +0 -28
  103. data/lib/mongo_mapper/serialization.rb +0 -54
  104. data/lib/mongo_mapper/serializers/json_serializer.rb +0 -48
  105. data/lib/mongo_mapper/validations.rb +0 -39
  106. data/test/functional/test_rails_compatibility.rb +0 -25
@@ -109,12 +109,6 @@ class Answer
109
109
  key :body, String
110
110
  end
111
111
 
112
- module PeopleExtensions
113
- def find_by_name(name)
114
- detect { |p| p.name == name }
115
- end
116
- end
117
-
118
112
  module CollaboratorsExtensions
119
113
  def top
120
114
  first
@@ -126,9 +120,7 @@ class Project
126
120
 
127
121
  key :name, String
128
122
 
129
- many :people, :extend => PeopleExtensions
130
123
  many :collaborators, :extend => CollaboratorsExtensions
131
-
132
124
  many :statuses, :order => 'position' do
133
125
  def open
134
126
  all(:name => %w(New Assigned))
@@ -163,37 +155,6 @@ class Status
163
155
  belongs_to :target, :polymorphic => true
164
156
  end
165
157
 
166
- class RealPerson
167
- include MongoMapper::Document
168
-
169
- key :room_id, ObjectId
170
- key :name, String
171
-
172
- belongs_to :room
173
-
174
- many :pets
175
-
176
- def realname=(n)
177
- self.name = n
178
- end
179
- end
180
-
181
- class Person
182
- include MongoMapper::EmbeddedDocument
183
-
184
- key :name, String
185
- key :child, Person
186
-
187
- many :pets
188
- end
189
-
190
- class Pet
191
- include MongoMapper::EmbeddedDocument
192
-
193
- key :name, String
194
- key :species, String
195
- end
196
-
197
158
  class Media
198
159
  include MongoMapper::EmbeddedDocument
199
160
 
@@ -16,12 +16,46 @@ require 'support/timing'
16
16
 
17
17
  class Test::Unit::TestCase
18
18
  include CustomMatchers
19
+
20
+ def Doc(name=nil, &block)
21
+ klass = Class.new do
22
+ include MongoMapper::Document
23
+ set_collection_name "test#{rand(20)}"
24
+
25
+ if name
26
+ class_eval "def self.name; '#{name}' end"
27
+ class_eval "def self.to_s; '#{name}' end"
28
+ end
29
+ end
30
+
31
+ klass.class_eval(&block) if block_given?
32
+ klass.collection.remove
33
+ klass
34
+ end
35
+
36
+ def EDoc(name=nil, &block)
37
+ klass = Class.new do
38
+ include MongoMapper::EmbeddedDocument
39
+
40
+ if name
41
+ class_eval "def self.name; '#{name}' end"
42
+ class_eval "def self.to_s; '#{name}' end"
43
+ end
44
+ end
45
+
46
+ klass.class_eval(&block) if block_given?
47
+ klass
48
+ end
49
+
50
+ def drop_indexes(klass)
51
+ if klass.database.collection_names.include?(klass.collection.name)
52
+ klass.collection.drop_indexes
53
+ end
54
+ end
19
55
  end
20
56
 
21
57
  test_dir = File.expand_path(File.dirname(__FILE__) + '/../tmp')
22
58
  FileUtils.mkdir_p(test_dir) unless File.exist?(test_dir)
23
59
 
24
- MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017, {
25
- :logger => Logger.new(test_dir + '/test.log')
26
- })
60
+ MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017, {:logger => Logger.new(test_dir + '/test.log')})
27
61
  MongoMapper.database = 'test'
@@ -4,7 +4,7 @@ require 'models'
4
4
  class FooMonster; end
5
5
 
6
6
  class AssociationBaseTest < Test::Unit::TestCase
7
- include MongoMapper::Associations
7
+ include MongoMapper::Plugins::Associations
8
8
 
9
9
  should "initialize with type and name" do
10
10
  base = Base.new(:many, :foos)
@@ -104,20 +104,20 @@ class AssociationBaseTest < Test::Unit::TestCase
104
104
  end
105
105
  end
106
106
 
107
- context "finder_options" do
107
+ context "query_options" do
108
108
  should "default to empty hash" do
109
109
  base = Base.new(:many, :foos)
110
- base.finder_options.should == {}
110
+ base.query_options.should == {}
111
111
  end
112
112
 
113
113
  should "work with order" do
114
114
  base = Base.new(:many, :foos, :order => 'position')
115
- base.finder_options.should == {:order => 'position'}
115
+ base.query_options.should == {:order => 'position'}
116
116
  end
117
117
 
118
118
  should "correctly parse from options" do
119
119
  base = Base.new(:many, :foos, :order => 'position', :somekey => 'somevalue')
120
- base.finder_options.should == {:order => 'position', :somekey => 'somevalue'}
120
+ base.query_options.should == {:order => 'position', :somekey => 'somevalue'}
121
121
  end
122
122
  end
123
123
 
@@ -1,17 +1,19 @@
1
1
  require 'test_helper'
2
2
 
3
- class FakeNilProxy < MongoMapper::Associations::Proxy
3
+ class FakeNilProxy < MongoMapper::Plugins::Associations::Proxy
4
4
  def find_target; nil end
5
5
  end
6
6
 
7
- class FakeBlankProxy < MongoMapper::Associations::Proxy
7
+ class FakeBlankProxy < MongoMapper::Plugins::Associations::Proxy
8
8
  def find_target; '' end
9
9
  end
10
10
 
11
- class FakeProxy < MongoMapper::Associations::Proxy
12
- def find_target
13
- [1, 2]
14
- end
11
+ class FakeNumberProxy < MongoMapper::Plugins::Associations::Proxy
12
+ def find_target; 17 end
13
+ end
14
+
15
+ class FakeProxy < MongoMapper::Plugins::Associations::Proxy
16
+ def find_target; [1, 2] end
15
17
  end
16
18
 
17
19
  class ProxyTest < Test::Unit::TestCase
@@ -0,0 +1,71 @@
1
+ require 'test_helper'
2
+
3
+ class DescendantAppendsTest < Test::Unit::TestCase
4
+ context "Document" do
5
+ should "default descendants to a new set" do
6
+ MongoMapper::Document.descendants.should be_instance_of(Set)
7
+ end
8
+
9
+ should 'allow extensions to Document to be appended' do
10
+ module Extension; def test_this_extension; end end
11
+ MongoMapper::Document.append_extensions(Extension)
12
+ article = Doc()
13
+ article.should respond_to(:test_this_extension)
14
+ end
15
+
16
+ should 'add appended extensions to classes that include Document before they are added' do
17
+ module Extension; def test_this_extension; end end
18
+ article = Doc()
19
+ MongoMapper::Document.append_extensions(Extension)
20
+ article.should respond_to(:test_this_extension)
21
+ end
22
+
23
+ should 'allow inclusions to Document to be appended' do
24
+ module Inclusion; def test_this_inclusion; end end
25
+ MongoMapper::Document.append_inclusions(Inclusion)
26
+ article = Doc()
27
+ article.new.should respond_to(:test_this_inclusion)
28
+ end
29
+
30
+ should 'add appended inclusions to classes that include Document before they are added' do
31
+ module Inclusion; def test_this_inclusion; end end
32
+ article = Doc()
33
+ MongoMapper::Document.append_inclusions(Inclusion)
34
+ article.new.should respond_to(:test_this_inclusion)
35
+ end
36
+ end
37
+
38
+ context "EmbeddedDocument" do
39
+ should "default descendants to a new set" do
40
+ MongoMapper::EmbeddedDocument.descendants.should be_instance_of(Set)
41
+ end
42
+
43
+ should 'allow extensions to Document to be appended' do
44
+ module Extension; def test_this_extension; end end
45
+ MongoMapper::EmbeddedDocument.append_extensions(Extension)
46
+ article = EDoc()
47
+ article.should respond_to(:test_this_extension)
48
+ end
49
+
50
+ should 'add appended extensions to classes that include Document before they are added' do
51
+ module Extension; def test_this_extension; end end
52
+ article = EDoc()
53
+ MongoMapper::EmbeddedDocument.append_extensions(Extension)
54
+ article.should respond_to(:test_this_extension)
55
+ end
56
+
57
+ should 'allow inclusions to Document to be appended' do
58
+ module Inclusion; def test_this_inclusion; end end
59
+ MongoMapper::EmbeddedDocument.append_inclusions(Inclusion)
60
+ article = EDoc()
61
+ article.new.should respond_to(:test_this_inclusion)
62
+ end
63
+
64
+ should 'add appended inclusions to classes that include Document before they are added' do
65
+ module Inclusion; def test_this_inclusion; end end
66
+ article = EDoc()
67
+ MongoMapper::EmbeddedDocument.append_inclusions(Inclusion)
68
+ article.new.should respond_to(:test_this_inclusion)
69
+ end
70
+ end
71
+ end
@@ -4,21 +4,17 @@ require 'models'
4
4
  class DocumentTest < Test::Unit::TestCase
5
5
  context "The Document Class" do
6
6
  setup do
7
- @document = Class.new do
8
- include MongoMapper::Document
9
- set_collection_name 'test'
10
- end
11
- @document.collection.remove
7
+ @document = Doc()
8
+ end
9
+
10
+ should "return false for embeddable" do
11
+ Doc().embeddable?.should be_false
12
12
  end
13
13
 
14
14
  should "have logger method" do
15
15
  @document.logger.should == MongoMapper.logger
16
16
  @document.logger.should be_instance_of(Logger)
17
17
  end
18
-
19
- should "track its descendants" do
20
- MongoMapper::Document.descendants.should include(@document)
21
- end
22
18
 
23
19
  should "use default database by default" do
24
20
  @document.database.should == MongoMapper.database
@@ -40,10 +36,7 @@ class DocumentTest < Test::Unit::TestCase
40
36
  @document.database_name.should == 'test2'
41
37
  @document.database.name.should == 'test2'
42
38
 
43
- another_document = Class.new do
44
- include MongoMapper::Document
45
- set_collection_name 'test'
46
- end
39
+ another_document = Doc()
47
40
  another_document.database.should == MongoMapper.database
48
41
  end
49
42
 
@@ -72,38 +65,6 @@ class DocumentTest < Test::Unit::TestCase
72
65
  @document.collection.should be_instance_of(Mongo::Collection)
73
66
  @document.collection.name.should == 'foobar'
74
67
  end
75
-
76
- should 'allow extensions to Document to be appended' do
77
- module Extension; def test_this_extension; end end
78
- MongoMapper::Document.append_extensions(Extension)
79
- article = Class.new { include MongoMapper::Document }
80
-
81
- article.should respond_to(:test_this_extension)
82
- end
83
-
84
- should 'add appended extensions to classes that include Document before they are added' do
85
- module Extension; def test_this_extension; end end
86
- article = Class.new { include MongoMapper::Document }
87
- MongoMapper::Document.append_extensions(Extension)
88
-
89
- article.should respond_to(:test_this_extension)
90
- end
91
-
92
- should 'allow inclusions to Document to be appended' do
93
- module Inclusion; def test_this_inclusion; end end
94
- MongoMapper::Document.append_inclusions(Inclusion)
95
- article = Class.new { include MongoMapper::Document }
96
-
97
- article.new.should respond_to(:test_this_inclusion)
98
- end
99
-
100
- should 'add appended inclusions to classes that include Document before they are added' do
101
- module Inclusion; def test_this_inclusion; end end
102
- article = Class.new { include MongoMapper::Document }
103
- MongoMapper::Document.append_inclusions(Inclusion)
104
-
105
- article.new.should respond_to(:test_this_inclusion)
106
- end
107
68
  end # Document class
108
69
 
109
70
  context "Documents that inherit from other documents" do
@@ -113,29 +74,41 @@ class DocumentTest < Test::Unit::TestCase
113
74
  Exit.collection_name.should == 'messages'
114
75
  Chat.collection_name.should == 'messages'
115
76
  end
116
-
77
+
117
78
  should "default associations to inherited class" do
118
- Message.associations.keys.should include("room")
119
- Enter.associations.keys.should include("room")
120
- Exit.associations.keys.should include("room")
121
- Chat.associations.keys.should include("room")
122
- end
123
-
124
- should "track subclasses" do
125
- Message.subclasses.should == [Enter, Exit, Chat]
79
+ Message.associations.keys.should include("room")
80
+ Enter.associations.keys.should include("room")
81
+ Exit.associations.keys.should include("room")
82
+ Chat.associations.keys.should include("room")
83
+ end
84
+ end
85
+
86
+ context "descendants" do
87
+ should "default to nil" do
88
+ Enter.descendants.should be_nil
89
+ end
90
+
91
+ should "be recorded" do
92
+ Message.descendants.should == [Enter, Exit, Chat]
126
93
  end
127
94
  end
128
95
 
129
96
  context "An instance of a document" do
130
97
  setup do
131
- @document = Class.new do
132
- include MongoMapper::Document
133
- set_collection_name 'test'
134
-
98
+ @document = Doc do
135
99
  key :name, String
136
100
  key :age, Integer
137
101
  end
138
- @document.collection.remove
102
+ end
103
+
104
+ should "create id during initialization" do
105
+ @document.new._id.should be_instance_of(Mongo::ObjectID)
106
+ end
107
+
108
+ should "have to_param that is string representation of id" do
109
+ doc = @document.new(:id => Mongo::ObjectID.new)
110
+ doc.to_param.should == doc.id.to_s
111
+ doc.to_param.should be_instance_of(String)
139
112
  end
140
113
 
141
114
  should "have access to logger" do
@@ -164,18 +137,10 @@ class DocumentTest < Test::Unit::TestCase
164
137
  end
165
138
 
166
139
  context "root document" do
167
- should "have a nil _root_document" do
168
- @document.new._root_document.should be_nil
169
- end
170
-
171
140
  should "set self to the root document on embedded documents" do
172
- klass = Class.new do
173
- include MongoMapper::Document
174
- end
141
+ klass = Doc()
142
+ pets = EDoc()
175
143
 
176
- pets = Class.new do
177
- include MongoMapper::EmbeddedDocument
178
- end
179
144
  klass.many :pets, :class => pets
180
145
 
181
146
  doc = klass.new(:pets => [{}])
@@ -197,7 +162,7 @@ class DocumentTest < Test::Unit::TestCase
197
162
  end
198
163
 
199
164
  context "clone" do
200
- should "not set the id" do
165
+ should "be new" do
201
166
  doc = @document.create(:name => "foo", :age => 27)
202
167
  clone = doc.clone
203
168
  clone.should be_new
@@ -211,10 +176,44 @@ class DocumentTest < Test::Unit::TestCase
211
176
  end
212
177
  end
213
178
 
179
+ should "call inspect on the document's attributes instead of to_s when inspecting the document" do
180
+ doc = @document.new(:animals => %w(dog cat))
181
+ doc.inspect.should include(%(animals: ["dog", "cat"]))
182
+ end
183
+
214
184
  context "equality" do
215
185
  setup do
216
186
  @oid = Mongo::ObjectID.new
217
187
  end
188
+
189
+ should "delegate hash to _id" do
190
+ doc = @document.new
191
+ doc.hash.should == doc._id.hash
192
+ end
193
+
194
+ should "delegate eql to ==" do
195
+ doc = @document.new
196
+ other = @document.new
197
+ doc.eql?(other).should == (doc == other)
198
+ doc.eql?(doc).should == (doc == doc)
199
+ end
200
+
201
+ should "know if same object as another" do
202
+ doc = @document.new
203
+ doc.should equal(doc)
204
+ doc.should_not equal(@document.new)
205
+ end
206
+
207
+ should "allow set operations on array of documents" do
208
+ @document.key :parent_id, ObjectId
209
+ @document.belongs_to :parent, :class => @document
210
+
211
+ parent = @document.create
212
+ child = @document.create(:parent => parent)
213
+
214
+ ([child.parent] & [parent]).should == [parent]
215
+ end
216
+
218
217
  should "be equal if id and class are the same" do
219
218
  (@document.new('_id' => @oid) == @document.new('_id' => @oid)).should be(true)
220
219
  end
@@ -224,12 +223,8 @@ class DocumentTest < Test::Unit::TestCase
224
223
  end
225
224
 
226
225
  should "not be equal if id same but class different" do
227
- @another_document = Class.new do
228
- include MongoMapper::Document
229
- set_collection_name 'test'
230
- end
231
-
232
- (@document.new('_id' => @oid) == @another_document.new('_id' => @oid)).should be(false)
226
+ another_document = Doc()
227
+ (@document.new('_id' => @oid) == another_document.new('_id' => @oid)).should be(false)
233
228
  end
234
229
  end
235
230
  end # instance of a document