jnunemaker-mongomapper 0.2.0 → 0.3.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 +1 -0
- data/History +17 -0
- data/README.rdoc +6 -3
- data/Rakefile +3 -2
- data/VERSION +1 -1
- data/bin/mmconsole +56 -0
- data/lib/mongomapper.rb +48 -17
- data/lib/mongomapper/associations.rb +31 -39
- data/lib/mongomapper/associations/base.rb +40 -22
- data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +33 -0
- data/lib/mongomapper/associations/belongs_to_proxy.rb +10 -14
- data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +34 -0
- data/lib/mongomapper/associations/{has_many_embedded_proxy.rb → many_embedded_proxy.rb} +5 -5
- data/lib/mongomapper/associations/many_proxy.rb +55 -0
- data/lib/mongomapper/associations/proxy.rb +21 -14
- data/lib/mongomapper/callbacks.rb +1 -1
- data/lib/mongomapper/document.rb +82 -59
- data/lib/mongomapper/embedded_document.rb +121 -130
- data/lib/mongomapper/finder_options.rb +21 -6
- data/lib/mongomapper/key.rb +5 -7
- data/lib/mongomapper/observing.rb +1 -41
- data/lib/mongomapper/pagination.rb +52 -0
- data/lib/mongomapper/rails_compatibility/document.rb +15 -0
- data/lib/mongomapper/rails_compatibility/embedded_document.rb +25 -0
- data/lib/mongomapper/serialization.rb +1 -1
- data/mongomapper.gemspec +62 -36
- data/test/NOTE_ON_TESTING +1 -0
- data/test/functional/test_associations.rb +485 -0
- data/test/{test_callbacks.rb → functional/test_callbacks.rb} +2 -1
- data/test/functional/test_document.rb +636 -0
- data/test/functional/test_pagination.rb +82 -0
- data/test/functional/test_rails_compatibility.rb +31 -0
- data/test/functional/test_validations.rb +172 -0
- data/test/models.rb +92 -0
- data/test/test_helper.rb +5 -0
- data/test/{serializers → unit/serializers}/test_json_serializer.rb +0 -0
- data/test/unit/test_association_base.rb +131 -0
- data/test/unit/test_document.rb +115 -0
- data/test/{test_embedded_document.rb → unit/test_embedded_document.rb} +158 -66
- data/test/{test_finder_options.rb → unit/test_finder_options.rb} +66 -0
- data/test/{test_key.rb → unit/test_key.rb} +13 -1
- data/test/unit/test_mongo_id.rb +35 -0
- data/test/{test_mongomapper.rb → unit/test_mongomapper.rb} +0 -0
- data/test/{test_observing.rb → unit/test_observing.rb} +0 -0
- data/test/unit/test_pagination.rb +113 -0
- data/test/unit/test_rails_compatibility.rb +34 -0
- data/test/{test_serializations.rb → unit/test_serializations.rb} +0 -2
- data/test/{test_validations.rb → unit/test_validations.rb} +0 -134
- metadata +68 -36
- data/lib/mongomapper/associations/has_many_proxy.rb +0 -28
- data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +0 -31
- data/lib/mongomapper/rails_compatibility.rb +0 -23
- data/test/test_associations.rb +0 -149
- data/test/test_document.rb +0 -944
- data/test/test_rails_compatibility.rb +0 -29
@@ -0,0 +1,52 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Pagination
|
3
|
+
class PaginationProxy < BasicObject
|
4
|
+
attr_accessor :subject
|
5
|
+
attr_reader :total_entries, :per_page, :current_page
|
6
|
+
alias limit per_page
|
7
|
+
|
8
|
+
def initialize(total_entries, current_page, per_page=nil)
|
9
|
+
@total_entries = total_entries.to_i
|
10
|
+
self.per_page = per_page
|
11
|
+
self.current_page = current_page
|
12
|
+
end
|
13
|
+
|
14
|
+
def total_pages
|
15
|
+
(total_entries / per_page.to_f).ceil
|
16
|
+
end
|
17
|
+
|
18
|
+
def out_of_bounds?
|
19
|
+
current_page > total_pages
|
20
|
+
end
|
21
|
+
|
22
|
+
def previous_page
|
23
|
+
current_page > 1 ? (current_page - 1) : nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def next_page
|
27
|
+
current_page < total_pages ? (current_page + 1) : nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def skip
|
31
|
+
(current_page - 1) * per_page
|
32
|
+
end
|
33
|
+
alias offset skip
|
34
|
+
|
35
|
+
def method_missing(name, *args, &block)
|
36
|
+
@subject.send(name, *args, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def per_page=(value)
|
41
|
+
value = 25 if value.blank?
|
42
|
+
@per_page = value.to_i
|
43
|
+
end
|
44
|
+
|
45
|
+
def current_page=(value)
|
46
|
+
value = value.to_i
|
47
|
+
value = 1 if value < 1
|
48
|
+
@current_page = value
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module RailsCompatibility
|
3
|
+
module EmbeddedDocument
|
4
|
+
def self.included(model)
|
5
|
+
model.class_eval do
|
6
|
+
extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
class << model
|
10
|
+
alias has_many many
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def column_names
|
16
|
+
keys.keys
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_param
|
21
|
+
raise "Missing to_param method in #{self.class}. You should implement it to return the unique identifier of this embedded document within a document."
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/mongomapper.gemspec
CHANGED
@@ -2,12 +2,14 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{mongomapper}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.3.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["John Nunemaker"]
|
9
|
-
s.date = %q{2009-07-
|
9
|
+
s.date = %q{2009-07-28}
|
10
|
+
s.default_executable = %q{mmconsole}
|
10
11
|
s.email = %q{nunemaker@gmail.com}
|
12
|
+
s.executables = ["mmconsole"]
|
11
13
|
s.extra_rdoc_files = [
|
12
14
|
"LICENSE",
|
13
15
|
"README.rdoc"
|
@@ -19,14 +21,16 @@ Gem::Specification.new do |s|
|
|
19
21
|
"README.rdoc",
|
20
22
|
"Rakefile",
|
21
23
|
"VERSION",
|
24
|
+
"bin/mmconsole",
|
22
25
|
"lib/mongomapper.rb",
|
23
26
|
"lib/mongomapper/associations.rb",
|
24
27
|
"lib/mongomapper/associations/array_proxy.rb",
|
25
28
|
"lib/mongomapper/associations/base.rb",
|
29
|
+
"lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb",
|
26
30
|
"lib/mongomapper/associations/belongs_to_proxy.rb",
|
27
|
-
"lib/mongomapper/associations/
|
28
|
-
"lib/mongomapper/associations/
|
29
|
-
"lib/mongomapper/associations/
|
31
|
+
"lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb",
|
32
|
+
"lib/mongomapper/associations/many_embedded_proxy.rb",
|
33
|
+
"lib/mongomapper/associations/many_proxy.rb",
|
30
34
|
"lib/mongomapper/associations/proxy.rb",
|
31
35
|
"lib/mongomapper/callbacks.rb",
|
32
36
|
"lib/mongomapper/document.rb",
|
@@ -34,25 +38,36 @@ Gem::Specification.new do |s|
|
|
34
38
|
"lib/mongomapper/finder_options.rb",
|
35
39
|
"lib/mongomapper/key.rb",
|
36
40
|
"lib/mongomapper/observing.rb",
|
37
|
-
"lib/mongomapper/
|
41
|
+
"lib/mongomapper/pagination.rb",
|
42
|
+
"lib/mongomapper/rails_compatibility/document.rb",
|
43
|
+
"lib/mongomapper/rails_compatibility/embedded_document.rb",
|
38
44
|
"lib/mongomapper/save_with_validation.rb",
|
39
45
|
"lib/mongomapper/serialization.rb",
|
40
46
|
"lib/mongomapper/serializers/json_serializer.rb",
|
41
47
|
"lib/mongomapper/validations.rb",
|
42
48
|
"mongomapper.gemspec",
|
43
|
-
"test/
|
44
|
-
"test/test_associations.rb",
|
45
|
-
"test/test_callbacks.rb",
|
46
|
-
"test/test_document.rb",
|
47
|
-
"test/
|
48
|
-
"test/
|
49
|
+
"test/NOTE_ON_TESTING",
|
50
|
+
"test/functional/test_associations.rb",
|
51
|
+
"test/functional/test_callbacks.rb",
|
52
|
+
"test/functional/test_document.rb",
|
53
|
+
"test/functional/test_pagination.rb",
|
54
|
+
"test/functional/test_rails_compatibility.rb",
|
55
|
+
"test/functional/test_validations.rb",
|
56
|
+
"test/models.rb",
|
49
57
|
"test/test_helper.rb",
|
50
|
-
"test/
|
51
|
-
"test/
|
52
|
-
"test/
|
53
|
-
"test/
|
54
|
-
"test/
|
55
|
-
"test/
|
58
|
+
"test/unit/serializers/test_json_serializer.rb",
|
59
|
+
"test/unit/test_association_base.rb",
|
60
|
+
"test/unit/test_document.rb",
|
61
|
+
"test/unit/test_embedded_document.rb",
|
62
|
+
"test/unit/test_finder_options.rb",
|
63
|
+
"test/unit/test_key.rb",
|
64
|
+
"test/unit/test_mongo_id.rb",
|
65
|
+
"test/unit/test_mongomapper.rb",
|
66
|
+
"test/unit/test_observing.rb",
|
67
|
+
"test/unit/test_pagination.rb",
|
68
|
+
"test/unit/test_rails_compatibility.rb",
|
69
|
+
"test/unit/test_serializations.rb",
|
70
|
+
"test/unit/test_validations.rb"
|
56
71
|
]
|
57
72
|
s.has_rdoc = true
|
58
73
|
s.homepage = %q{http://github.com/jnunemaker/mongomapper}
|
@@ -62,19 +77,27 @@ Gem::Specification.new do |s|
|
|
62
77
|
s.rubygems_version = %q{1.3.1}
|
63
78
|
s.summary = %q{Awesome gem for modeling your domain and storing it in mongo}
|
64
79
|
s.test_files = [
|
65
|
-
"test/
|
66
|
-
"test/
|
67
|
-
"test/
|
68
|
-
"test/
|
69
|
-
"test/
|
70
|
-
"test/
|
80
|
+
"test/functional/test_associations.rb",
|
81
|
+
"test/functional/test_callbacks.rb",
|
82
|
+
"test/functional/test_document.rb",
|
83
|
+
"test/functional/test_pagination.rb",
|
84
|
+
"test/functional/test_rails_compatibility.rb",
|
85
|
+
"test/functional/test_validations.rb",
|
86
|
+
"test/models.rb",
|
71
87
|
"test/test_helper.rb",
|
72
|
-
"test/
|
73
|
-
"test/
|
74
|
-
"test/
|
75
|
-
"test/
|
76
|
-
"test/
|
77
|
-
"test/
|
88
|
+
"test/unit/serializers/test_json_serializer.rb",
|
89
|
+
"test/unit/test_association_base.rb",
|
90
|
+
"test/unit/test_document.rb",
|
91
|
+
"test/unit/test_embedded_document.rb",
|
92
|
+
"test/unit/test_finder_options.rb",
|
93
|
+
"test/unit/test_key.rb",
|
94
|
+
"test/unit/test_mongo_id.rb",
|
95
|
+
"test/unit/test_mongomapper.rb",
|
96
|
+
"test/unit/test_observing.rb",
|
97
|
+
"test/unit/test_pagination.rb",
|
98
|
+
"test/unit/test_rails_compatibility.rb",
|
99
|
+
"test/unit/test_serializations.rb",
|
100
|
+
"test/unit/test_validations.rb"
|
78
101
|
]
|
79
102
|
|
80
103
|
if s.respond_to? :specification_version then
|
@@ -83,21 +106,24 @@ Gem::Specification.new do |s|
|
|
83
106
|
|
84
107
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
85
108
|
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
86
|
-
s.add_runtime_dependency(%q<mongodb-mongo>, ["= 0.
|
87
|
-
s.add_runtime_dependency(%q<jnunemaker-validatable>, ["= 1.7.
|
109
|
+
s.add_runtime_dependency(%q<mongodb-mongo>, ["= 0.10.1"])
|
110
|
+
s.add_runtime_dependency(%q<jnunemaker-validatable>, ["= 1.7.2"])
|
111
|
+
s.add_runtime_dependency(%q<deep_merge>, ["= 0.1.0"])
|
88
112
|
s.add_development_dependency(%q<mocha>, ["= 0.9.4"])
|
89
113
|
s.add_development_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
|
90
114
|
else
|
91
115
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
92
|
-
s.add_dependency(%q<mongodb-mongo>, ["= 0.
|
93
|
-
s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.
|
116
|
+
s.add_dependency(%q<mongodb-mongo>, ["= 0.10.1"])
|
117
|
+
s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.2"])
|
118
|
+
s.add_dependency(%q<deep_merge>, ["= 0.1.0"])
|
94
119
|
s.add_dependency(%q<mocha>, ["= 0.9.4"])
|
95
120
|
s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
|
96
121
|
end
|
97
122
|
else
|
98
123
|
s.add_dependency(%q<activesupport>, [">= 0"])
|
99
|
-
s.add_dependency(%q<mongodb-mongo>, ["= 0.
|
100
|
-
s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.
|
124
|
+
s.add_dependency(%q<mongodb-mongo>, ["= 0.10.1"])
|
125
|
+
s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.2"])
|
126
|
+
s.add_dependency(%q<deep_merge>, ["= 0.1.0"])
|
101
127
|
s.add_dependency(%q<mocha>, ["= 0.9.4"])
|
102
128
|
s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
|
103
129
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
I am doing my best to keep unit and functional tests separate. As I see them, functional tests hit the database and should never care about internals. Unit tests do not hit the database.
|
@@ -0,0 +1,485 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'models'
|
3
|
+
|
4
|
+
class AssociationsTest < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
clear_all_collections
|
7
|
+
end
|
8
|
+
|
9
|
+
context "Modularized Polymorphic Many Embedded" do
|
10
|
+
should "set associations correctly" do
|
11
|
+
fleet_attributes = {
|
12
|
+
"name" => "My Fleet",
|
13
|
+
"transports" => [
|
14
|
+
{"_type" => "TrModels::Ambulance", "license_plate" => "GGG123", "icu" => true},
|
15
|
+
{"_type" => "TrModels::Car", "license_plate" => "ABC123", "model" => "VW Golf", "year" => 2001},
|
16
|
+
{"_type" => "TrModels::Car", "license_plate" => "DEF123", "model" => "Honda Accord", "year" => 2008},
|
17
|
+
]
|
18
|
+
}
|
19
|
+
|
20
|
+
fleet = TrModels::Fleet.new(fleet_attributes)
|
21
|
+
fleet.transports.size.should == 3
|
22
|
+
fleet.transports[0].class.should == TrModels::Ambulance
|
23
|
+
fleet.transports[0].license_plate.should == "GGG123"
|
24
|
+
fleet.transports[0].icu.should be_true
|
25
|
+
fleet.transports[1].class.should == TrModels::Car
|
26
|
+
fleet.transports[1].license_plate.should == "ABC123"
|
27
|
+
fleet.transports[1].model.should == "VW Golf"
|
28
|
+
fleet.transports[1].year.should == 2001
|
29
|
+
fleet.transports[2].class.should == TrModels::Car
|
30
|
+
fleet.transports[2].license_plate.should == "DEF123"
|
31
|
+
fleet.transports[2].model.should == "Honda Accord"
|
32
|
+
fleet.transports[2].year.should == 2008
|
33
|
+
fleet.save.should be_true
|
34
|
+
|
35
|
+
from_db = TrModels::Fleet.find(fleet.id)
|
36
|
+
from_db.transports.size.should == 3
|
37
|
+
from_db.transports[0].license_plate.should == "GGG123"
|
38
|
+
from_db.transports[0].icu.should be_true
|
39
|
+
from_db.transports[1].license_plate.should == "ABC123"
|
40
|
+
from_db.transports[1].model.should == "VW Golf"
|
41
|
+
from_db.transports[1].year.should == 2001
|
42
|
+
from_db.transports[2].license_plate.should == "DEF123"
|
43
|
+
from_db.transports[2].model.should == "Honda Accord"
|
44
|
+
from_db.transports[2].year.should == 2008
|
45
|
+
end
|
46
|
+
|
47
|
+
should "default reader to empty array" do
|
48
|
+
fleet = TrModels::Fleet.new
|
49
|
+
fleet.transports.should == []
|
50
|
+
end
|
51
|
+
|
52
|
+
should "allow adding to association like it was an array" do
|
53
|
+
fleet = TrModels::Fleet.new
|
54
|
+
fleet.transports << TrModels::Car.new
|
55
|
+
fleet.transports.push TrModels::Bus.new
|
56
|
+
fleet.transports.size.should == 2
|
57
|
+
end
|
58
|
+
|
59
|
+
should "store the association" do
|
60
|
+
fleet = TrModels::Fleet.new
|
61
|
+
fleet.transports = [TrModels::Car.new("license_plate" => "DCU2013", "model" => "Honda Civic")]
|
62
|
+
fleet.save.should be_true
|
63
|
+
|
64
|
+
from_db = TrModels::Fleet.find(fleet.id)
|
65
|
+
from_db.transports.size.should == 1
|
66
|
+
from_db.transports[0].license_plate.should == "DCU2013"
|
67
|
+
end
|
68
|
+
|
69
|
+
should "store different associations" do
|
70
|
+
fleet = TrModels::Fleet.new
|
71
|
+
fleet.transports = [
|
72
|
+
TrModels::Car.new("license_plate" => "ABC1223", "model" => "Honda Civic", "year" => 2003),
|
73
|
+
TrModels::Bus.new("license_plate" => "XYZ9090", "max_passengers" => 51),
|
74
|
+
TrModels::Ambulance.new("license_plate" => "HDD3030", "icu" => true)
|
75
|
+
]
|
76
|
+
fleet.save.should be_true
|
77
|
+
|
78
|
+
from_db = TrModels::Fleet.find(fleet.id)
|
79
|
+
from_db.transports.size.should == 3
|
80
|
+
from_db.transports[0].license_plate.should == "ABC1223"
|
81
|
+
from_db.transports[0].model.should == "Honda Civic"
|
82
|
+
from_db.transports[0].year.should == 2003
|
83
|
+
from_db.transports[1].license_plate.should == "XYZ9090"
|
84
|
+
from_db.transports[1].max_passengers.should == 51
|
85
|
+
from_db.transports[2].license_plate.should == "HDD3030"
|
86
|
+
from_db.transports[2].icu.should == true
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "Polymorphic Many Embedded" do
|
91
|
+
should "default reader to empty array" do
|
92
|
+
catalog = Catalog.new
|
93
|
+
catalog.medias.should == []
|
94
|
+
end
|
95
|
+
|
96
|
+
should "allow adding to association like it was an array" do
|
97
|
+
catalog = Catalog.new
|
98
|
+
catalog.medias << Video.new
|
99
|
+
catalog.medias.push Video.new
|
100
|
+
catalog.medias.size.should == 2
|
101
|
+
end
|
102
|
+
|
103
|
+
should "store the association" do
|
104
|
+
catalog = Catalog.new
|
105
|
+
catalog.medias = [Video.new("file" => "video.mpg", "length" => 3600)]
|
106
|
+
catalog.save.should be_true
|
107
|
+
|
108
|
+
from_db = Catalog.find(catalog.id)
|
109
|
+
from_db.medias.size.should == 1
|
110
|
+
from_db.medias[0].file.should == "video.mpg"
|
111
|
+
end
|
112
|
+
|
113
|
+
should "store different associations" do
|
114
|
+
catalog = Catalog.new
|
115
|
+
catalog.medias = [
|
116
|
+
Video.new("file" => "video.mpg", "length" => 3600),
|
117
|
+
Music.new("file" => "music.mp3", "bitrate" => "128kbps"),
|
118
|
+
Image.new("file" => "image.png", "width" => 800, "height" => 600)
|
119
|
+
]
|
120
|
+
catalog.save.should be_true
|
121
|
+
|
122
|
+
from_db = Catalog.find(catalog.id)
|
123
|
+
from_db.medias.size.should == 3
|
124
|
+
from_db.medias[0].file.should == "video.mpg"
|
125
|
+
from_db.medias[0].length.should == 3600
|
126
|
+
from_db.medias[1].file.should == "music.mp3"
|
127
|
+
from_db.medias[1].bitrate.should == "128kbps"
|
128
|
+
from_db.medias[2].file.should == "image.png"
|
129
|
+
from_db.medias[2].width.should == 800
|
130
|
+
from_db.medias[2].height.should == 600
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "Polymorphic Belongs To" do
|
135
|
+
should "default to nil" do
|
136
|
+
status = Status.new
|
137
|
+
status.target.should be_nil
|
138
|
+
end
|
139
|
+
|
140
|
+
should "store the association" do
|
141
|
+
status = Status.new
|
142
|
+
project = Project.new(:name => "mongomapper")
|
143
|
+
status.target = project
|
144
|
+
status.save.should be_true
|
145
|
+
|
146
|
+
from_db = Status.find(status.id)
|
147
|
+
from_db.target.should_not be_nil
|
148
|
+
from_db.target_id.should == project.id
|
149
|
+
from_db.target_type.should == "Project"
|
150
|
+
from_db.target.name.should == "mongomapper"
|
151
|
+
end
|
152
|
+
|
153
|
+
should "unset the association" do
|
154
|
+
status = Status.new
|
155
|
+
project = Project.new(:name => "mongomapper")
|
156
|
+
status.target = project
|
157
|
+
status.save.should be_true
|
158
|
+
|
159
|
+
from_db = Status.find(status.id)
|
160
|
+
from_db.target = nil
|
161
|
+
from_db.target_type.should be_nil
|
162
|
+
from_db.target_id.should be_nil
|
163
|
+
from_db.target.should be_nil
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "Belongs To" do
|
168
|
+
should "default to nil" do
|
169
|
+
status = Status.new
|
170
|
+
status.project.should be_nil
|
171
|
+
end
|
172
|
+
|
173
|
+
should "store the association" do
|
174
|
+
status = Status.new
|
175
|
+
project = Project.new(:name => "mongomapper")
|
176
|
+
status.project = project
|
177
|
+
status.save.should be_true
|
178
|
+
|
179
|
+
from_db = Status.find(status.id)
|
180
|
+
from_db.project.should_not be_nil
|
181
|
+
from_db.project.name.should == "mongomapper"
|
182
|
+
end
|
183
|
+
|
184
|
+
should "unset the association" do
|
185
|
+
status = Status.new
|
186
|
+
project = Project.new(:name => "mongomapper")
|
187
|
+
status.project = project
|
188
|
+
status.save.should be_true
|
189
|
+
|
190
|
+
from_db = Status.find(status.id)
|
191
|
+
from_db.project = nil
|
192
|
+
from_db.project.should be_nil
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
context "Many documents" do
|
197
|
+
should "default reader to empty array" do
|
198
|
+
project = Project.new
|
199
|
+
project.statuses.should == []
|
200
|
+
end
|
201
|
+
|
202
|
+
should "allow adding to association like it was an array" do
|
203
|
+
project = Project.new
|
204
|
+
project.statuses << Status.new
|
205
|
+
project.statuses.push Status.new
|
206
|
+
project.statuses.size.should == 2
|
207
|
+
end
|
208
|
+
|
209
|
+
should "store the association" do
|
210
|
+
project = Project.new
|
211
|
+
project.statuses = [Status.new("name" => "ready")]
|
212
|
+
project.save.should be_true
|
213
|
+
|
214
|
+
from_db = Project.find(project.id)
|
215
|
+
from_db.statuses.size.should == 1
|
216
|
+
from_db.statuses[0].name.should == "ready"
|
217
|
+
end
|
218
|
+
|
219
|
+
context "Finding scoped to association" do
|
220
|
+
setup do
|
221
|
+
@project1 = Project.new(:name => 'Project 1')
|
222
|
+
@brand_new = Status.create(:name => 'New')
|
223
|
+
@complete = Status.create(:name => 'Complete')
|
224
|
+
@project1.statuses = [@brand_new, @complete]
|
225
|
+
@project1.save
|
226
|
+
|
227
|
+
@project2 = Project.create(:name => 'Project 2')
|
228
|
+
@in_progress = Status.create(:name => 'In Progress')
|
229
|
+
@archived = Status.create(:name => 'Archived')
|
230
|
+
@another_complete = Status.create(:name => 'Complete')
|
231
|
+
@project2.statuses = [@in_progress, @archived, @another_complete]
|
232
|
+
@project2.save
|
233
|
+
end
|
234
|
+
|
235
|
+
context "with :all" do
|
236
|
+
should "work" do
|
237
|
+
@project1.statuses.find(:all).should == [@brand_new, @complete]
|
238
|
+
end
|
239
|
+
|
240
|
+
should "work with conditions" do
|
241
|
+
statuses = @project1.statuses.find(:all, :conditions => {'name' => 'Complete'})
|
242
|
+
statuses.should == [@complete]
|
243
|
+
end
|
244
|
+
|
245
|
+
should "work with order" do
|
246
|
+
statuses = @project1.statuses.find(:all, :order => 'name asc')
|
247
|
+
statuses.should == [@complete, @brand_new]
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
context "with #all" do
|
252
|
+
should "work" do
|
253
|
+
@project1.statuses.all.should == [@brand_new, @complete]
|
254
|
+
end
|
255
|
+
|
256
|
+
should "work with conditions" do
|
257
|
+
statuses = @project1.statuses.all(:conditions => {'name' => 'Complete'})
|
258
|
+
statuses.should == [@complete]
|
259
|
+
end
|
260
|
+
|
261
|
+
should "work with order" do
|
262
|
+
statuses = @project1.statuses.all(:order => 'name asc')
|
263
|
+
statuses.should == [@complete, @brand_new]
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
context "with :first" do
|
268
|
+
should "work" do
|
269
|
+
@project1.statuses.find(:first).should == @brand_new
|
270
|
+
end
|
271
|
+
|
272
|
+
should "work with conditions" do
|
273
|
+
status = @project1.statuses.find(:first, :conditions => {:name => 'Complete'})
|
274
|
+
status.should == @complete
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
context "with #first" do
|
279
|
+
should "work" do
|
280
|
+
@project1.statuses.first.should == @brand_new
|
281
|
+
end
|
282
|
+
|
283
|
+
should "work with conditions" do
|
284
|
+
status = @project1.statuses.first(:conditions => {:name => 'Complete'})
|
285
|
+
status.should == @complete
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
context "with :last" do
|
290
|
+
should "work" do
|
291
|
+
@project1.statuses.find(:last).should == @complete
|
292
|
+
end
|
293
|
+
|
294
|
+
should "work with conditions" do
|
295
|
+
status = @project1.statuses.find(:last, :conditions => {:name => 'New'})
|
296
|
+
status.should == @brand_new
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
context "with #last" do
|
301
|
+
should "work" do
|
302
|
+
@project1.statuses.last.should == @complete
|
303
|
+
end
|
304
|
+
|
305
|
+
should "work with conditions" do
|
306
|
+
status = @project1.statuses.last(:conditions => {:name => 'New'})
|
307
|
+
status.should == @brand_new
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
context "with one id" do
|
312
|
+
should "work for id in association" do
|
313
|
+
@project1.statuses.find(@complete.id).should == @complete
|
314
|
+
end
|
315
|
+
|
316
|
+
should "not work for id not in association" do
|
317
|
+
lambda {
|
318
|
+
@project1.statuses.find(@archived.id)
|
319
|
+
}.should raise_error(MongoMapper::DocumentNotFound)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
context "with multiple ids" do
|
324
|
+
should "work for ids in association" do
|
325
|
+
statuses = @project1.statuses.find(@brand_new.id, @complete.id)
|
326
|
+
statuses.should == [@brand_new, @complete]
|
327
|
+
end
|
328
|
+
|
329
|
+
should "not work for ids not in association" do
|
330
|
+
lambda {
|
331
|
+
@project1.statuses.find(@brand_new.id, @complete.id, @archived.id)
|
332
|
+
}.should raise_error(MongoMapper::DocumentNotFound)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
context "with #paginate" do
|
337
|
+
setup do
|
338
|
+
@statuses = @project2.statuses.paginate(:per_page => 2, :page => 1)
|
339
|
+
end
|
340
|
+
|
341
|
+
should "return total pages" do
|
342
|
+
@statuses.total_pages.should == 2
|
343
|
+
end
|
344
|
+
|
345
|
+
should "return total entries" do
|
346
|
+
@statuses.total_entries.should == 3
|
347
|
+
end
|
348
|
+
|
349
|
+
should "return the subject" do
|
350
|
+
@statuses.should == [@in_progress, @archived]
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
context "Many embedded documents" do
|
357
|
+
should "allow adding to association like it was an array" do
|
358
|
+
project = Project.new
|
359
|
+
project.addresses << Address.new
|
360
|
+
project.addresses.push Address.new
|
361
|
+
project.addresses.size.should == 2
|
362
|
+
end
|
363
|
+
|
364
|
+
should "be embedded in document on save" do
|
365
|
+
sb = Address.new(:city => 'South Bend', :state => 'IN')
|
366
|
+
chi = Address.new(:city => 'Chicago', :state => 'IL')
|
367
|
+
project = Project.new
|
368
|
+
project.addresses << sb
|
369
|
+
project.addresses << chi
|
370
|
+
project.save
|
371
|
+
|
372
|
+
from_db = Project.find(project.id)
|
373
|
+
from_db.addresses.size.should == 2
|
374
|
+
from_db.addresses[0].should == sb
|
375
|
+
from_db.addresses[1].should == chi
|
376
|
+
end
|
377
|
+
|
378
|
+
should "allow embedding arbitrarily deep" do
|
379
|
+
@document = Class.new do
|
380
|
+
include MongoMapper::Document
|
381
|
+
key :person, Person
|
382
|
+
end
|
383
|
+
@document.collection.clear
|
384
|
+
|
385
|
+
meg = Person.new(:name => "Meg")
|
386
|
+
meg.child = Person.new(:name => "Steve")
|
387
|
+
meg.child.child = Person.new(:name => "Linda")
|
388
|
+
|
389
|
+
doc = @document.new(:person => meg)
|
390
|
+
doc.save
|
391
|
+
|
392
|
+
from_db = @document.find(doc.id)
|
393
|
+
from_db.person.name.should == 'Meg'
|
394
|
+
from_db.person.child.name.should == 'Steve'
|
395
|
+
from_db.person.child.child.name.should == 'Linda'
|
396
|
+
end
|
397
|
+
|
398
|
+
should "allow assignment of 'many' embedded documents using a hash" do
|
399
|
+
person_attributes = {
|
400
|
+
"name" => "Mr. Pet Lover",
|
401
|
+
"pets" => [
|
402
|
+
{"name" => "Jimmy", "species" => "Cocker Spainel"},
|
403
|
+
{"name" => "Sasha", "species" => "Siberian Husky"},
|
404
|
+
]
|
405
|
+
}
|
406
|
+
|
407
|
+
pet_lover = RealPerson.new(person_attributes)
|
408
|
+
pet_lover.name.should == "Mr. Pet Lover"
|
409
|
+
pet_lover.pets[0].name.should == "Jimmy"
|
410
|
+
pet_lover.pets[0].species.should == "Cocker Spainel"
|
411
|
+
pet_lover.pets[1].name.should == "Sasha"
|
412
|
+
pet_lover.pets[1].species.should == "Siberian Husky"
|
413
|
+
pet_lover.save.should be_true
|
414
|
+
|
415
|
+
from_db = RealPerson.find(pet_lover.id)
|
416
|
+
from_db.name.should == "Mr. Pet Lover"
|
417
|
+
from_db.pets[0].name.should == "Jimmy"
|
418
|
+
from_db.pets[0].species.should == "Cocker Spainel"
|
419
|
+
from_db.pets[1].name.should == "Sasha"
|
420
|
+
from_db.pets[1].species.should == "Siberian Husky"
|
421
|
+
end
|
422
|
+
|
423
|
+
should "allow saving embedded documents in 'many' embedded documents" do
|
424
|
+
@document = Class.new do
|
425
|
+
include MongoMapper::Document
|
426
|
+
many :people
|
427
|
+
end
|
428
|
+
@document.collection.clear
|
429
|
+
|
430
|
+
meg = Person.new(:name => "Meg")
|
431
|
+
sparky = Pet.new(:name => "Sparky", :species => "Dog")
|
432
|
+
koda = Pet.new(:name => "Koda", :species => "Dog")
|
433
|
+
|
434
|
+
doc = @document.new
|
435
|
+
|
436
|
+
meg.pets << sparky
|
437
|
+
meg.pets << koda
|
438
|
+
|
439
|
+
doc.people << meg
|
440
|
+
doc.save
|
441
|
+
|
442
|
+
from_db = @document.find(doc.id)
|
443
|
+
from_db.people.first.name.should == "Meg"
|
444
|
+
from_db.people.first.pets.should_not == []
|
445
|
+
from_db.people.first.pets.first.name.should == "Sparky"
|
446
|
+
from_db.people.first.pets.first.species.should == "Dog"
|
447
|
+
from_db.people.first.pets[1].name.should == "Koda"
|
448
|
+
from_db.people.first.pets[1].species.should == "Dog"
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
context "Changing association class names" do
|
453
|
+
should "work for many and belongs to" do
|
454
|
+
class AwesomeUser
|
455
|
+
include MongoMapper::Document
|
456
|
+
many :posts, :class_name => 'AssociationsTest::AwesomePost', :foreign_key => :creator_id
|
457
|
+
end
|
458
|
+
|
459
|
+
class AwesomeTag
|
460
|
+
include MongoMapper::EmbeddedDocument
|
461
|
+
key :name, String
|
462
|
+
belongs_to :post, :class_name => 'AssociationsTest::AwesomeUser'
|
463
|
+
end
|
464
|
+
|
465
|
+
class AwesomePost
|
466
|
+
include MongoMapper::Document
|
467
|
+
belongs_to :creator, :class_name => 'AssociationsTest::AwesomeUser'
|
468
|
+
many :tags, :class_name => 'AssociationsTest::AwesomeTag', :foreign_key => :post_id
|
469
|
+
end
|
470
|
+
|
471
|
+
AwesomeUser.collection.clear
|
472
|
+
AwesomePost.collection.clear
|
473
|
+
|
474
|
+
user = AwesomeUser.create
|
475
|
+
tag1 = AwesomeTag.new(:name => 'awesome')
|
476
|
+
tag2 = AwesomeTag.new(:name => 'grand')
|
477
|
+
post1 = AwesomePost.create(:creator => user, :tags => [tag1])
|
478
|
+
post2 = AwesomePost.create(:creator => user, :tags => [tag2])
|
479
|
+
user.posts.should == [post1, post2]
|
480
|
+
|
481
|
+
post1_from_db = AwesomePost.find(post1.id)
|
482
|
+
post1_from_db.tags.should == [tag1]
|
483
|
+
end
|
484
|
+
end
|
485
|
+
end
|