fcoury-mongomapper 0.2.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.
- data/.gitignore +7 -0
- data/History +30 -0
- data/LICENSE +20 -0
- data/README.rdoc +39 -0
- data/Rakefile +71 -0
- data/VERSION +1 -0
- data/lib/mongomapper.rb +70 -0
- data/lib/mongomapper/associations.rb +69 -0
- data/lib/mongomapper/associations/array_proxy.rb +6 -0
- data/lib/mongomapper/associations/base.rb +54 -0
- data/lib/mongomapper/associations/belongs_to_proxy.rb +26 -0
- data/lib/mongomapper/associations/has_many_embedded_proxy.rb +19 -0
- data/lib/mongomapper/associations/has_many_proxy.rb +29 -0
- data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +31 -0
- data/lib/mongomapper/associations/proxy.rb +66 -0
- data/lib/mongomapper/callbacks.rb +106 -0
- data/lib/mongomapper/document.rb +276 -0
- data/lib/mongomapper/document_rails_compatibility.rb +13 -0
- data/lib/mongomapper/embedded_document.rb +248 -0
- data/lib/mongomapper/embedded_document_rails_compatibility.rb +22 -0
- data/lib/mongomapper/finder_options.rb +81 -0
- data/lib/mongomapper/key.rb +82 -0
- data/lib/mongomapper/observing.rb +50 -0
- data/lib/mongomapper/save_with_validation.rb +19 -0
- data/lib/mongomapper/serialization.rb +55 -0
- data/lib/mongomapper/serializers/json_serializer.rb +77 -0
- data/lib/mongomapper/validations.rb +47 -0
- data/mongomapper.gemspec +105 -0
- data/test/serializers/test_json_serializer.rb +104 -0
- data/test/test_associations.rb +444 -0
- data/test/test_callbacks.rb +84 -0
- data/test/test_document.rb +1002 -0
- data/test/test_embedded_document.rb +253 -0
- data/test/test_finder_options.rb +148 -0
- data/test/test_helper.rb +62 -0
- data/test/test_key.rb +200 -0
- data/test/test_mongomapper.rb +28 -0
- data/test/test_observing.rb +101 -0
- data/test/test_rails_compatibility.rb +73 -0
- data/test/test_serializations.rb +54 -0
- data/test/test_validations.rb +409 -0
- metadata +155 -0
data/test/test_key.rb
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Address
|
4
|
+
include MongoMapper::EmbeddedDocument
|
5
|
+
|
6
|
+
key :address, String
|
7
|
+
key :city, String
|
8
|
+
key :state, String
|
9
|
+
key :zip, Integer
|
10
|
+
end
|
11
|
+
|
12
|
+
class KeyTest < Test::Unit::TestCase
|
13
|
+
include MongoMapper
|
14
|
+
|
15
|
+
context "The Key Class" do
|
16
|
+
should "have the native types defined" do
|
17
|
+
Key::NativeTypes.should == [String, Float, Time, Integer, Boolean, Array, Hash, Ref]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "Initializing a new key" do
|
22
|
+
should "allow setting the name" do
|
23
|
+
Key.new(:foo, String).name.should == 'foo'
|
24
|
+
end
|
25
|
+
|
26
|
+
should "allow setting the type" do
|
27
|
+
Key.new(:foo, Integer).type.should be(Integer)
|
28
|
+
end
|
29
|
+
|
30
|
+
should "allow setting options" do
|
31
|
+
Key.new(:foo, Integer, :required => true).options[:required].should be(true)
|
32
|
+
end
|
33
|
+
|
34
|
+
should "symbolize option keys" do
|
35
|
+
Key.new(:foo, Integer, 'required' => true).options[:required].should be(true)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "A key" do
|
40
|
+
should "be equal to another key with same name and type" do
|
41
|
+
Key.new(:name, String).should == Key.new(:name, String)
|
42
|
+
end
|
43
|
+
|
44
|
+
should "not be equal to another key with different name" do
|
45
|
+
Key.new(:name, String).should_not == Key.new(:foo, String)
|
46
|
+
end
|
47
|
+
|
48
|
+
should "not be equal to another key with different type" do
|
49
|
+
Key.new(:name, String).should_not == Key.new(:name, Integer)
|
50
|
+
end
|
51
|
+
|
52
|
+
should "know if it is native" do
|
53
|
+
Key.new(:name, String).native?.should be_true
|
54
|
+
end
|
55
|
+
|
56
|
+
should "know if it is not native" do
|
57
|
+
klass = Class.new
|
58
|
+
Key.new(:name, klass).native?.should be_false
|
59
|
+
end
|
60
|
+
|
61
|
+
should "know if it is a embedded_document" do
|
62
|
+
klass = Class.new do
|
63
|
+
include MongoMapper::EmbeddedDocument
|
64
|
+
end
|
65
|
+
Key.new(:name, klass).embedded_document?.should be_true
|
66
|
+
end
|
67
|
+
|
68
|
+
should "know if it is not a embedded_document" do
|
69
|
+
Key.new(:name, String).embedded_document?.should be_false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "setting a value" do
|
74
|
+
should "correctly typecast Strings" do
|
75
|
+
key = Key.new(:foo, String)
|
76
|
+
[21, '21'].each do |a|
|
77
|
+
key.set(a).should == '21'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
should "correctly typecast Integers" do
|
82
|
+
key = Key.new(:foo, Integer)
|
83
|
+
[21, 21.0, '21'].each do |a|
|
84
|
+
key.set(a).should == 21
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
should "correctly typecast Floats" do
|
89
|
+
key = Key.new(:foo, Float)
|
90
|
+
[21, 21.0, '21'].each do |a|
|
91
|
+
key.set(a).should == 21.0
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
should "correctly typecast Times" do
|
96
|
+
key = Key.new(:foo, Time)
|
97
|
+
key.set('2000-01-01 01:01:01.123456').should == Time.local(2000, 1, 1, 1, 1, 1, 123456)
|
98
|
+
end
|
99
|
+
|
100
|
+
should_eventually "correctly typecast Dates" do
|
101
|
+
key = Key.new(:foo, Date)
|
102
|
+
key.set('2000-01-01').should == Date.new(2000, 1, 1)
|
103
|
+
end
|
104
|
+
|
105
|
+
should "correctly typecast Boolean" do
|
106
|
+
key = Key.new(:foo, Boolean)
|
107
|
+
['false', false, 'f', '0', 0].each do |b|
|
108
|
+
key.set(b).should == false
|
109
|
+
end
|
110
|
+
|
111
|
+
['true', true, 't', '1', 1].each do |b|
|
112
|
+
key.set(b).should == true
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
should "correctly typecast Array" do
|
117
|
+
key = Key.new(:foo, Array)
|
118
|
+
key.set([1,2,3,4]).should == [1,2,3,4]
|
119
|
+
key.set({'1' => '2', '3' => '4'}).should == [['1', '2'], ['3', '4']]
|
120
|
+
key.set('1').should == ['1']
|
121
|
+
end
|
122
|
+
|
123
|
+
should "correctly typecast Hash using indifferent access" do
|
124
|
+
key = Key.new(:foo, Hash)
|
125
|
+
key.set(:foo => 'bar')[:foo].should == 'bar'
|
126
|
+
key.set(:foo => 'bar')['foo'].should == 'bar'
|
127
|
+
key.set(:foo => {:bar => 'baz'})[:foo][:bar].should == 'baz'
|
128
|
+
key.set(:foo => {:bar => 'baz'})['foo']['bar'].should == 'baz'
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context "getting a value" do
|
133
|
+
should "work" do
|
134
|
+
key = Key.new(:foo, String)
|
135
|
+
key.get('bar').should == 'bar'
|
136
|
+
end
|
137
|
+
|
138
|
+
context "for a key with a default value set" do
|
139
|
+
setup do
|
140
|
+
@key = Key.new(:foo, String, :default => 'baz')
|
141
|
+
end
|
142
|
+
|
143
|
+
should "return default value if value nil" do
|
144
|
+
@key.get(nil).should == 'baz'
|
145
|
+
end
|
146
|
+
|
147
|
+
should "return value if not blank" do
|
148
|
+
@key.get('foobar').should == 'foobar'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "for a boolean key" do
|
153
|
+
should "allow setting default to false" do
|
154
|
+
Key.new(:active, Boolean, :default => false).get(nil).should be_false
|
155
|
+
end
|
156
|
+
|
157
|
+
should "allow setting default to true" do
|
158
|
+
Key.new(:active, Boolean, :default => true).get(nil).should be_true
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "for an array" do
|
163
|
+
should "return array" do
|
164
|
+
key = Key.new(:foo, Array)
|
165
|
+
key.get([1,2]).should == [1,2]
|
166
|
+
end
|
167
|
+
|
168
|
+
should "default to empty array" do
|
169
|
+
key = Key.new(:foo, Array)
|
170
|
+
key.get(nil).should == []
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context "for a hash" do
|
175
|
+
should "default to empty hash" do
|
176
|
+
key = Key.new(:foo, Hash)
|
177
|
+
key.get(nil).should == {}
|
178
|
+
end
|
179
|
+
|
180
|
+
should "use hash with indifferent access" do
|
181
|
+
key = Key.new(:foo, Hash)
|
182
|
+
key.get({:foo => 'bar'})['foo'].should == 'bar'
|
183
|
+
key.get({:foo => 'bar'})[:foo].should == 'bar'
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context "for a embedded_document" do
|
188
|
+
should "default to nil" do
|
189
|
+
key = Key.new(:foo, Address)
|
190
|
+
key.get(nil).should be_nil
|
191
|
+
end
|
192
|
+
|
193
|
+
should "return instance if instance" do
|
194
|
+
address = Address.new(:city => 'South Bend', :state => 'IN', :zip => 46544)
|
195
|
+
key = Key.new(:foo, Address)
|
196
|
+
key.get(address).should == address
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end # KeyTest
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Address; end
|
4
|
+
|
5
|
+
class MongoMapperTest < Test::Unit::TestCase
|
6
|
+
should "be able to write and read connection" do
|
7
|
+
conn = XGen::Mongo::Driver::Mongo.new
|
8
|
+
MongoMapper.connection = conn
|
9
|
+
MongoMapper.connection.should == conn
|
10
|
+
end
|
11
|
+
|
12
|
+
should "default connection to new mongo ruby driver" do
|
13
|
+
MongoMapper.connection = nil
|
14
|
+
MongoMapper.connection.should be_instance_of(XGen::Mongo::Driver::Mongo)
|
15
|
+
end
|
16
|
+
|
17
|
+
should "be able to write and read default database" do
|
18
|
+
MongoMapper.database = DefaultDatabase
|
19
|
+
MongoMapper.database.should be_instance_of(XGen::Mongo::Driver::DB)
|
20
|
+
MongoMapper.database.name.should == DefaultDatabase
|
21
|
+
end
|
22
|
+
|
23
|
+
should "have document not found error" do
|
24
|
+
lambda {
|
25
|
+
MongoMapper::DocumentNotFound
|
26
|
+
}.should_not raise_error
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Comment
|
4
|
+
include MongoMapper::Document
|
5
|
+
|
6
|
+
key :name, String
|
7
|
+
key :body, String
|
8
|
+
|
9
|
+
attr_accessor :callers
|
10
|
+
before_validation :record_callers
|
11
|
+
|
12
|
+
def after_validation
|
13
|
+
record_callers
|
14
|
+
end
|
15
|
+
|
16
|
+
def record_callers
|
17
|
+
callers << self.class if callers
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Article
|
22
|
+
include MongoMapper::Document
|
23
|
+
|
24
|
+
key :title, String
|
25
|
+
key :body, String
|
26
|
+
end
|
27
|
+
|
28
|
+
class CommentObserver < MongoMapper::Observer
|
29
|
+
attr_accessor :callers
|
30
|
+
|
31
|
+
def after_validation(model)
|
32
|
+
callers << self.class if callers
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class AuditObserver < MongoMapper::Observer
|
37
|
+
observe Article, Comment
|
38
|
+
attr_reader :document
|
39
|
+
|
40
|
+
def after_validation(document)
|
41
|
+
@document = document
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class GlobalObserver < MongoMapper::Observer
|
46
|
+
observe Article, Comment
|
47
|
+
attr_reader :document
|
48
|
+
|
49
|
+
def before_save(document)
|
50
|
+
@document = document
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class NonAutomaticObserver < MongoMapper::Observer
|
55
|
+
observe Comment
|
56
|
+
attr_reader :comment
|
57
|
+
|
58
|
+
def after_validation(comment)
|
59
|
+
@comment = comment
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class ObserverTest < Test::Unit::TestCase
|
64
|
+
should "fire model callbacks before observer" do
|
65
|
+
callers = []
|
66
|
+
comment = Comment.new
|
67
|
+
comment.callers = callers
|
68
|
+
|
69
|
+
CommentObserver.instance.callers = callers
|
70
|
+
|
71
|
+
comment.valid?
|
72
|
+
callers.should == [Comment, Comment, CommentObserver]
|
73
|
+
end
|
74
|
+
|
75
|
+
should "automatically observe model based on name when possible" do
|
76
|
+
CommentObserver.observed_class.should == Comment
|
77
|
+
end
|
78
|
+
|
79
|
+
should "be able to observe other models using observe" do
|
80
|
+
obs = NonAutomaticObserver.instance
|
81
|
+
comment = Comment.new(:name => 'John Nunemaker', :body => 'is awesome')
|
82
|
+
comment.valid?
|
83
|
+
obs.comment.name.should == 'John Nunemaker'
|
84
|
+
obs.comment.body.should == 'is awesome'
|
85
|
+
end
|
86
|
+
|
87
|
+
should "be able to observe multiple models" do
|
88
|
+
obs = AuditObserver.instance
|
89
|
+
comment = Comment.new(:name => 'Steve Smith', :body => 'is awesome')
|
90
|
+
comment.valid?
|
91
|
+
|
92
|
+
obs.document.name.should == 'Steve Smith'
|
93
|
+
obs.document.body.should == 'is awesome'
|
94
|
+
|
95
|
+
article = Article.new(:title => 'Ordered List Is Awesome', :body => 'Learn to accept it!')
|
96
|
+
article.valid?
|
97
|
+
|
98
|
+
obs.document.title.should == 'Ordered List Is Awesome'
|
99
|
+
obs.document.body.should == 'Learn to accept it!'
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Item
|
4
|
+
include MongoMapper::EmbeddedDocument
|
5
|
+
key :for_all, String
|
6
|
+
end
|
7
|
+
|
8
|
+
class FirstItem < Item
|
9
|
+
key :first_only, String
|
10
|
+
end
|
11
|
+
|
12
|
+
class SecondItem < Item
|
13
|
+
key :second_only, String
|
14
|
+
end
|
15
|
+
|
16
|
+
class Order
|
17
|
+
include MongoMapper::Document
|
18
|
+
many :items, :polymorphic => true, :class_name => "Item"
|
19
|
+
key :order_only, String
|
20
|
+
end
|
21
|
+
|
22
|
+
class TestRailsCompatibility < Test::Unit::TestCase
|
23
|
+
def setup
|
24
|
+
@document = Class.new do
|
25
|
+
include MongoMapper::Document
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "EmbeddedDocument" do
|
30
|
+
should "have to_param that returns id" do
|
31
|
+
first_item = FirstItem.new
|
32
|
+
second_item = SecondItem.new
|
33
|
+
|
34
|
+
order = Order.create('_id' => '1234')
|
35
|
+
order.items = [
|
36
|
+
first_item,
|
37
|
+
second_item
|
38
|
+
]
|
39
|
+
order.to_param.should == '1234'
|
40
|
+
|
41
|
+
lambda { first_item.to_param }.should raise_error
|
42
|
+
lambda { second_item.to_param }.should raise_error
|
43
|
+
end
|
44
|
+
|
45
|
+
should "have column names" do
|
46
|
+
Order.column_names.sort.should == ['_id', 'created_at', 'order_only', 'updated_at']
|
47
|
+
FirstItem.column_names.sort.should == ['first_only', 'for_all']
|
48
|
+
SecondItem.column_names.sort.should == ['for_all', 'second_only']
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "Document" do
|
53
|
+
should "have to_param that returns id" do
|
54
|
+
instance = @document.create('_id' => '1234')
|
55
|
+
instance.to_param.should == '1234'
|
56
|
+
end
|
57
|
+
|
58
|
+
should "alias new to new_record?" do
|
59
|
+
instance = @document.new
|
60
|
+
instance.new_record?.should == instance.new?
|
61
|
+
end
|
62
|
+
|
63
|
+
should "alias many to has_many" do
|
64
|
+
@document.should respond_to(:has_many)
|
65
|
+
@document.method(:has_many).should == @document.method(:many)
|
66
|
+
end
|
67
|
+
|
68
|
+
should "have column names" do
|
69
|
+
@document.key :fname, String
|
70
|
+
@document.column_names.sort.should == ['_id', 'created_at', 'fname', 'updated_at']
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class SerializationTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@document = Class.new do
|
6
|
+
include MongoMapper::EmbeddedDocument
|
7
|
+
key :name, String
|
8
|
+
key :age, Integer
|
9
|
+
key :awesome, Boolean
|
10
|
+
key :preferences, Hash
|
11
|
+
key :created_at, Time
|
12
|
+
end
|
13
|
+
|
14
|
+
@instance = @document.new(
|
15
|
+
:name => 'John Doe',
|
16
|
+
:age => 25,
|
17
|
+
:awesome => true,
|
18
|
+
:preferences => {:language => 'Ruby'},
|
19
|
+
:created_at => Time.now.change(:usec => 0)
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
# [:xml, :json].each do |format|
|
24
|
+
[:json].each do |format|
|
25
|
+
context format do
|
26
|
+
should "be reversable" do
|
27
|
+
serialized = @instance.send("to_#{format}")
|
28
|
+
unserialized = @document.new.send("from_#{format}", serialized)
|
29
|
+
|
30
|
+
assert_equal @instance, unserialized
|
31
|
+
end
|
32
|
+
|
33
|
+
should "allow attribute only filtering" do
|
34
|
+
serialized = @instance.send("to_#{format}", :only => [ :age, :name ])
|
35
|
+
unserialized = @document.new.send("from_#{format}", serialized)
|
36
|
+
|
37
|
+
assert_equal @instance.name, unserialized.name
|
38
|
+
assert_equal @instance.age, unserialized.age
|
39
|
+
assert_nil unserialized.awesome
|
40
|
+
assert_nil unserialized.created_at
|
41
|
+
end
|
42
|
+
|
43
|
+
should "allow attribute except filtering" do
|
44
|
+
serialized = @instance.send("to_#{format}", :except => [ :age, :name ])
|
45
|
+
unserialized = @document.new.send("from_#{format}", serialized)
|
46
|
+
|
47
|
+
assert_nil unserialized.name
|
48
|
+
assert_nil unserialized.age
|
49
|
+
assert_equal @instance.awesome, unserialized.awesome
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|