mongo_mapper 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/.gitignore +7 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +39 -0
  4. data/Rakefile +87 -0
  5. data/VERSION +1 -0
  6. data/bin/mmconsole +55 -0
  7. data/lib/mongo_mapper.rb +92 -0
  8. data/lib/mongo_mapper/associations.rb +86 -0
  9. data/lib/mongo_mapper/associations/base.rb +83 -0
  10. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +34 -0
  11. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +22 -0
  12. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +27 -0
  13. data/lib/mongo_mapper/associations/many_documents_proxy.rb +116 -0
  14. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +33 -0
  15. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +67 -0
  16. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +11 -0
  17. data/lib/mongo_mapper/associations/many_proxy.rb +6 -0
  18. data/lib/mongo_mapper/associations/proxy.rb +64 -0
  19. data/lib/mongo_mapper/callbacks.rb +106 -0
  20. data/lib/mongo_mapper/document.rb +317 -0
  21. data/lib/mongo_mapper/dynamic_finder.rb +35 -0
  22. data/lib/mongo_mapper/embedded_document.rb +354 -0
  23. data/lib/mongo_mapper/finder_options.rb +94 -0
  24. data/lib/mongo_mapper/key.rb +32 -0
  25. data/lib/mongo_mapper/observing.rb +50 -0
  26. data/lib/mongo_mapper/pagination.rb +51 -0
  27. data/lib/mongo_mapper/rails_compatibility/document.rb +15 -0
  28. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +27 -0
  29. data/lib/mongo_mapper/save_with_validation.rb +19 -0
  30. data/lib/mongo_mapper/serialization.rb +55 -0
  31. data/lib/mongo_mapper/serializers/json_serializer.rb +92 -0
  32. data/lib/mongo_mapper/support.rb +157 -0
  33. data/lib/mongo_mapper/validations.rb +69 -0
  34. data/mongo_mapper.gemspec +156 -0
  35. data/test/NOTE_ON_TESTING +1 -0
  36. data/test/custom_matchers.rb +48 -0
  37. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +54 -0
  38. data/test/functional/associations/test_belongs_to_proxy.rb +46 -0
  39. data/test/functional/associations/test_many_documents_as_proxy.rb +244 -0
  40. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +132 -0
  41. data/test/functional/associations/test_many_embedded_proxy.rb +174 -0
  42. data/test/functional/associations/test_many_polymorphic_proxy.rb +297 -0
  43. data/test/functional/associations/test_many_proxy.rb +331 -0
  44. data/test/functional/test_associations.rb +48 -0
  45. data/test/functional/test_binary.rb +18 -0
  46. data/test/functional/test_callbacks.rb +85 -0
  47. data/test/functional/test_document.rb +951 -0
  48. data/test/functional/test_embedded_document.rb +97 -0
  49. data/test/functional/test_pagination.rb +87 -0
  50. data/test/functional/test_rails_compatibility.rb +30 -0
  51. data/test/functional/test_validations.rb +279 -0
  52. data/test/models.rb +169 -0
  53. data/test/test_helper.rb +29 -0
  54. data/test/unit/serializers/test_json_serializer.rb +189 -0
  55. data/test/unit/test_association_base.rb +144 -0
  56. data/test/unit/test_document.rb +165 -0
  57. data/test/unit/test_dynamic_finder.rb +125 -0
  58. data/test/unit/test_embedded_document.rb +645 -0
  59. data/test/unit/test_finder_options.rb +193 -0
  60. data/test/unit/test_key.rb +163 -0
  61. data/test/unit/test_mongomapper.rb +28 -0
  62. data/test/unit/test_observing.rb +101 -0
  63. data/test/unit/test_pagination.rb +109 -0
  64. data/test/unit/test_rails_compatibility.rb +39 -0
  65. data/test/unit/test_serializations.rb +52 -0
  66. data/test/unit/test_support.rb +272 -0
  67. data/test/unit/test_time_zones.rb +40 -0
  68. data/test/unit/test_validations.rb +503 -0
  69. metadata +204 -0
@@ -0,0 +1,69 @@
1
+ module MongoMapper
2
+ module Validations
3
+ module Macros
4
+ def validates_uniqueness_of(*args)
5
+ add_validations(args, MongoMapper::Validations::ValidatesUniquenessOf)
6
+ end
7
+
8
+ def validates_exclusion_of(*args)
9
+ add_validations(args, MongoMapper::Validations::ValidatesExclusionOf)
10
+ end
11
+
12
+ def validates_inclusion_of(*args)
13
+ add_validations(args, MongoMapper::Validations::ValidatesInclusionOf)
14
+ end
15
+ end
16
+
17
+ class ValidatesUniquenessOf < Validatable::ValidationBase
18
+ option :scope
19
+
20
+ def valid?(instance)
21
+ doc = instance.class.find(:first, :conditions => {self.attribute => instance[attribute]}.merge(scope_conditions(instance)), :limit => 1)
22
+ doc.nil? || instance.id == doc.id
23
+ end
24
+
25
+ def message(instance)
26
+ super || "has already been taken"
27
+ end
28
+
29
+ def scope_conditions(instance)
30
+ return {} unless scope
31
+ Array(scope).inject({}) do |conditions, key|
32
+ conditions.merge(key => instance[key])
33
+ end
34
+ end
35
+ end
36
+
37
+ class ValidatesExclusionOf < Validatable::ValidationBase
38
+ required_option :within
39
+
40
+ def valid?(instance)
41
+ value = instance[attribute]
42
+ return true if allow_nil && value.nil?
43
+ return true if allow_blank && value.blank?
44
+
45
+ !within.include?(instance[attribute])
46
+ end
47
+
48
+ def message(instance)
49
+ super || "is reserved"
50
+ end
51
+ end
52
+
53
+ class ValidatesInclusionOf < Validatable::ValidationBase
54
+ required_option :within
55
+
56
+ def valid?(instance)
57
+ value = instance[attribute]
58
+ return true if allow_nil && value.nil?
59
+ return true if allow_blank && value.blank?
60
+
61
+ within.include?(value)
62
+ end
63
+
64
+ def message(instance)
65
+ super || "is not in the list"
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,156 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{mongo_mapper}
8
+ s.version = "0.5.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["John Nunemaker"]
12
+ s.date = %q{2009-10-07}
13
+ s.default_executable = %q{mmconsole}
14
+ s.email = %q{nunemaker@gmail.com}
15
+ s.executables = ["mmconsole"]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "bin/mmconsole",
27
+ "lib/mongo_mapper.rb",
28
+ "lib/mongo_mapper/associations.rb",
29
+ "lib/mongo_mapper/associations/base.rb",
30
+ "lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb",
31
+ "lib/mongo_mapper/associations/belongs_to_proxy.rb",
32
+ "lib/mongo_mapper/associations/many_documents_as_proxy.rb",
33
+ "lib/mongo_mapper/associations/many_documents_proxy.rb",
34
+ "lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb",
35
+ "lib/mongo_mapper/associations/many_embedded_proxy.rb",
36
+ "lib/mongo_mapper/associations/many_polymorphic_proxy.rb",
37
+ "lib/mongo_mapper/associations/many_proxy.rb",
38
+ "lib/mongo_mapper/associations/proxy.rb",
39
+ "lib/mongo_mapper/callbacks.rb",
40
+ "lib/mongo_mapper/document.rb",
41
+ "lib/mongo_mapper/dynamic_finder.rb",
42
+ "lib/mongo_mapper/embedded_document.rb",
43
+ "lib/mongo_mapper/finder_options.rb",
44
+ "lib/mongo_mapper/key.rb",
45
+ "lib/mongo_mapper/observing.rb",
46
+ "lib/mongo_mapper/pagination.rb",
47
+ "lib/mongo_mapper/rails_compatibility/document.rb",
48
+ "lib/mongo_mapper/rails_compatibility/embedded_document.rb",
49
+ "lib/mongo_mapper/save_with_validation.rb",
50
+ "lib/mongo_mapper/serialization.rb",
51
+ "lib/mongo_mapper/serializers/json_serializer.rb",
52
+ "lib/mongo_mapper/support.rb",
53
+ "lib/mongo_mapper/validations.rb",
54
+ "mongo_mapper.gemspec",
55
+ "test/NOTE_ON_TESTING",
56
+ "test/custom_matchers.rb",
57
+ "test/functional/associations/test_belongs_to_polymorphic_proxy.rb",
58
+ "test/functional/associations/test_belongs_to_proxy.rb",
59
+ "test/functional/associations/test_many_documents_as_proxy.rb",
60
+ "test/functional/associations/test_many_embedded_polymorphic_proxy.rb",
61
+ "test/functional/associations/test_many_embedded_proxy.rb",
62
+ "test/functional/associations/test_many_polymorphic_proxy.rb",
63
+ "test/functional/associations/test_many_proxy.rb",
64
+ "test/functional/test_associations.rb",
65
+ "test/functional/test_binary.rb",
66
+ "test/functional/test_callbacks.rb",
67
+ "test/functional/test_document.rb",
68
+ "test/functional/test_embedded_document.rb",
69
+ "test/functional/test_pagination.rb",
70
+ "test/functional/test_rails_compatibility.rb",
71
+ "test/functional/test_validations.rb",
72
+ "test/models.rb",
73
+ "test/test_helper.rb",
74
+ "test/unit/serializers/test_json_serializer.rb",
75
+ "test/unit/test_association_base.rb",
76
+ "test/unit/test_document.rb",
77
+ "test/unit/test_dynamic_finder.rb",
78
+ "test/unit/test_embedded_document.rb",
79
+ "test/unit/test_finder_options.rb",
80
+ "test/unit/test_key.rb",
81
+ "test/unit/test_mongomapper.rb",
82
+ "test/unit/test_observing.rb",
83
+ "test/unit/test_pagination.rb",
84
+ "test/unit/test_rails_compatibility.rb",
85
+ "test/unit/test_serializations.rb",
86
+ "test/unit/test_support.rb",
87
+ "test/unit/test_time_zones.rb",
88
+ "test/unit/test_validations.rb"
89
+ ]
90
+ s.homepage = %q{http://github.com/jnunemaker/mongomapper}
91
+ s.rdoc_options = ["--charset=UTF-8"]
92
+ s.require_paths = ["lib"]
93
+ s.rubyforge_project = %q{mongomapper}
94
+ s.rubygems_version = %q{1.3.5}
95
+ s.summary = %q{Awesome gem for modeling your domain and storing it in mongo}
96
+ s.test_files = [
97
+ "test/custom_matchers.rb",
98
+ "test/functional/associations/test_belongs_to_polymorphic_proxy.rb",
99
+ "test/functional/associations/test_belongs_to_proxy.rb",
100
+ "test/functional/associations/test_many_documents_as_proxy.rb",
101
+ "test/functional/associations/test_many_embedded_polymorphic_proxy.rb",
102
+ "test/functional/associations/test_many_embedded_proxy.rb",
103
+ "test/functional/associations/test_many_polymorphic_proxy.rb",
104
+ "test/functional/associations/test_many_proxy.rb",
105
+ "test/functional/test_associations.rb",
106
+ "test/functional/test_binary.rb",
107
+ "test/functional/test_callbacks.rb",
108
+ "test/functional/test_document.rb",
109
+ "test/functional/test_embedded_document.rb",
110
+ "test/functional/test_pagination.rb",
111
+ "test/functional/test_rails_compatibility.rb",
112
+ "test/functional/test_validations.rb",
113
+ "test/models.rb",
114
+ "test/test_helper.rb",
115
+ "test/unit/serializers/test_json_serializer.rb",
116
+ "test/unit/test_association_base.rb",
117
+ "test/unit/test_document.rb",
118
+ "test/unit/test_dynamic_finder.rb",
119
+ "test/unit/test_embedded_document.rb",
120
+ "test/unit/test_finder_options.rb",
121
+ "test/unit/test_key.rb",
122
+ "test/unit/test_mongomapper.rb",
123
+ "test/unit/test_observing.rb",
124
+ "test/unit/test_pagination.rb",
125
+ "test/unit/test_rails_compatibility.rb",
126
+ "test/unit/test_serializations.rb",
127
+ "test/unit/test_support.rb",
128
+ "test/unit/test_time_zones.rb",
129
+ "test/unit/test_validations.rb"
130
+ ]
131
+
132
+ if s.respond_to? :specification_version then
133
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
134
+ s.specification_version = 3
135
+
136
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
137
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
138
+ s.add_runtime_dependency(%q<mongo>, ["= 0.15"])
139
+ s.add_runtime_dependency(%q<jnunemaker-validatable>, ["= 1.7.3"])
140
+ s.add_development_dependency(%q<mocha>, ["= 0.9.4"])
141
+ s.add_development_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
142
+ else
143
+ s.add_dependency(%q<activesupport>, [">= 0"])
144
+ s.add_dependency(%q<mongo>, ["= 0.15"])
145
+ s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.3"])
146
+ s.add_dependency(%q<mocha>, ["= 0.9.4"])
147
+ s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
148
+ end
149
+ else
150
+ s.add_dependency(%q<activesupport>, [">= 0"])
151
+ s.add_dependency(%q<mongo>, ["= 0.15"])
152
+ s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.3"])
153
+ s.add_dependency(%q<mocha>, ["= 0.9.4"])
154
+ s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
155
+ end
156
+ 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,48 @@
1
+ module CustomMatchers
2
+ custom_matcher :be_nil do |receiver, matcher, args|
3
+ matcher.positive_failure_message = "Expected #{receiver} to be nil but it wasn't"
4
+ matcher.negative_failure_message = "Expected #{receiver} not to be nil but it was"
5
+ receiver.nil?
6
+ end
7
+
8
+ custom_matcher :be_blank do |receiver, matcher, args|
9
+ matcher.positive_failure_message = "Expected #{receiver} to be blank but it wasn't"
10
+ matcher.negative_failure_message = "Expected #{receiver} not to be blank but it was"
11
+ receiver.blank?
12
+ end
13
+
14
+ custom_matcher :be_true do |receiver, matcher, args|
15
+ matcher.positive_failure_message = "Expected #{receiver} to be true but it wasn't"
16
+ matcher.negative_failure_message = "Expected #{receiver} not to be true but it was"
17
+ receiver.eql?(true)
18
+ end
19
+
20
+ custom_matcher :be_false do |receiver, matcher, args|
21
+ matcher.positive_failure_message = "Expected #{receiver} to be false but it wasn't"
22
+ matcher.negative_failure_message = "Expected #{receiver} not to be false but it was"
23
+ receiver.eql?(false)
24
+ end
25
+
26
+ custom_matcher :be_valid do |receiver, matcher, args|
27
+ matcher.positive_failure_message = "Expected to be valid but it was invalid #{receiver.errors.inspect}"
28
+ matcher.negative_failure_message = "Expected to be invalid but it was valid #{receiver.errors.inspect}"
29
+ receiver.valid?
30
+ end
31
+
32
+ custom_matcher :have_error_on do |receiver, matcher, args|
33
+ receiver.valid?
34
+ attribute = args[0]
35
+ expected_message = args[1]
36
+
37
+ if expected_message.nil?
38
+ matcher.positive_failure_message = "#{receiver} had no errors on #{attribute}"
39
+ matcher.negative_failure_message = "#{receiver} had errors on #{attribute} #{receiver.errors.inspect}"
40
+ !receiver.errors.on(attribute).blank?
41
+ else
42
+ actual = receiver.errors.on(attribute)
43
+ matcher.positive_failure_message = %Q(Expected error on #{attribute} to be "#{expected_message}" but was "#{actual}")
44
+ matcher.negative_failure_message = %Q(Expected error on #{attribute} not to be "#{expected_message}" but was "#{actual}")
45
+ actual == expected_message
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,54 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Status.collection.clear
7
+ Project.collection.clear
8
+ end
9
+
10
+ should "default to nil" do
11
+ status = Status.new
12
+ status.target.should be_nil
13
+ end
14
+
15
+ should "be able to replace the association" do
16
+ status = Status.new
17
+ project = Project.new(:name => "mongomapper")
18
+ status.target = project
19
+ status.save.should be_true
20
+
21
+ from_db = Status.find(status.id)
22
+ from_db.target.should_not be_nil
23
+ from_db.target_id.should == project.id
24
+ from_db.target_type.should == "Project"
25
+ from_db.target.name.should == "mongomapper"
26
+ end
27
+
28
+ should "unset the association" do
29
+ status = Status.new
30
+ project = Project.new(:name => "mongomapper")
31
+ status.target = project
32
+ status.save.should be_true
33
+
34
+ from_db = Status.find(status.id)
35
+ from_db.target = nil
36
+ from_db.target_type.should be_nil
37
+ from_db.target_id.should be_nil
38
+ from_db.target.should be_nil
39
+ end
40
+
41
+ context "association id set but document not found" do
42
+ setup do
43
+ @status = Status.new
44
+ project = Project.new(:name => "mongomapper")
45
+ @status.target = project
46
+ @status.save.should be_true
47
+ project.destroy
48
+ end
49
+
50
+ should "return nil instead of raising error" do
51
+ @status.target.should be_nil
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class BelongsToProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Status.collection.clear
7
+ Project.collection.clear
8
+ end
9
+
10
+ should "default to nil" do
11
+ status = Status.new
12
+ status.project.should be_nil
13
+ end
14
+
15
+ should "be able to replace the association" do
16
+ status = Status.new
17
+ project = Project.new(:name => "mongomapper")
18
+ status.project = project
19
+ status.save.should be_true
20
+
21
+ from_db = Status.find(status.id)
22
+ from_db.project.should_not be_nil
23
+ from_db.project.name.should == "mongomapper"
24
+ end
25
+
26
+ should "unset the association" do
27
+ status = Status.new
28
+ project = Project.new(:name => "mongomapper")
29
+ status.project = project
30
+ status.save.should be_true
31
+
32
+ from_db = Status.find(status.id)
33
+ from_db.project = nil
34
+ from_db.project.should be_nil
35
+ end
36
+
37
+ context "association id set but document not found" do
38
+ setup do
39
+ @status = Status.new(:name => 'Foo', :project_id => '1234')
40
+ end
41
+
42
+ should "return nil instead of raising error" do
43
+ @status.project.should be_nil
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,244 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyDocumentsAsProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Post.collection.clear
7
+ PostComment.collection.clear
8
+ end
9
+
10
+ should "default reader to empty array" do
11
+ Post.new.comments.should == []
12
+ end
13
+
14
+ should "add type and id key to polymorphic class base" do
15
+ PostComment.keys.keys.should include('commentable_type')
16
+ PostComment.keys.keys.should include('commentable_id')
17
+ end
18
+
19
+ should "allow adding to association like it was an array" do
20
+ post = Post.new
21
+ post.comments << PostComment.new(:body => 'foo bar')
22
+ post.comments << PostComment.new(:body => 'baz')
23
+ post.comments.concat PostComment.new(:body => 'baz')
24
+
25
+ post.comments.size.should == 3
26
+ end
27
+
28
+ should "be able to replace the association" do
29
+ post = Post.new
30
+
31
+ lambda {
32
+ post.comments = [
33
+ PostComment.new(:body => 'foo'),
34
+ PostComment.new(:body => 'bar'),
35
+ PostComment.new(:body => 'baz')
36
+ ]
37
+ }.should change { PostComment.count }.by(3)
38
+
39
+ from_db = Post.find(post.id)
40
+ from_db.comments.size.should == 3
41
+ from_db.comments[0].body.should == 'foo'
42
+ from_db.comments[1].body.should == 'bar'
43
+ from_db.comments[2].body.should == 'baz'
44
+ end
45
+
46
+ context "build" do
47
+ should "assign foreign key" do
48
+ post = Post.new
49
+ comment = post.comments.build
50
+ comment.commentable_id.should == post.id
51
+ end
52
+
53
+ should "assign _type" do
54
+ post = Post.new
55
+ comment = post.comments.build
56
+ comment.commentable_type.should == "Post"
57
+ end
58
+
59
+ should "allow assigning attributes" do
60
+ post = Post.new
61
+ comment = post.comments.build(:body => 'foo bar')
62
+ comment.body.should == 'foo bar'
63
+ end
64
+ end
65
+
66
+ context "create" do
67
+ should "assign foreign key" do
68
+ post = Post.new
69
+ comment = post.comments.create
70
+ comment.commentable_id.should == post.id
71
+ end
72
+
73
+ should "assign _type" do
74
+ post = Post.new
75
+ comment = post.comments.create
76
+ comment.commentable_type.should == "Post"
77
+ end
78
+
79
+ should "save record" do
80
+ post = Post.new
81
+ lambda {
82
+ post.comments.create(:body => 'baz')
83
+ }.should change { PostComment.count }
84
+ end
85
+
86
+ should "allow passing attributes" do
87
+ post = Post.create
88
+ comment = post.comments.create(:body => 'foo bar')
89
+ comment.body.should == 'foo bar'
90
+ end
91
+ end
92
+
93
+ context "count" do
94
+ should "work scoped to association" do
95
+ post = Post.create
96
+ 3.times { post.comments.create(:body => 'foo bar') }
97
+
98
+ other_post = Post.create
99
+ 2.times { other_post.comments.create(:body => 'baz') }
100
+
101
+ post.comments.count.should == 3
102
+ other_post.comments.count.should == 2
103
+ end
104
+
105
+ should "work with conditions" do
106
+ post = Post.create
107
+ post.comments.create(:body => 'foo bar')
108
+ post.comments.create(:body => 'baz')
109
+ post.comments.create(:body => 'foo bar')
110
+
111
+ post.comments.count(:body => 'foo bar').should == 2
112
+ end
113
+ end
114
+
115
+ context "Finding scoped to association" do
116
+ setup do
117
+ @post = Post.new
118
+
119
+ @comment1 = PostComment.create(:body => 'comment1', :name => 'John')
120
+ @comment2 = PostComment.create(:body => 'comment2', :name => 'Steve')
121
+ @comment3 = PostComment.create(:body => 'comment3', :name => 'John')
122
+ @post.comments = [@comment1, @comment2]
123
+ @post.save
124
+
125
+ @post2 = Post.create(:body => "post #2")
126
+ @comment4 = PostComment.create(:body => 'comment1', :name => 'Chas')
127
+ @comment5 = PostComment.create(:body => 'comment2', :name => 'Dan')
128
+ @comment6 = PostComment.create(:body => 'comment3', :name => 'Ed')
129
+ @post2.comments = [@comment4, @comment5, @comment6]
130
+ @post2.save
131
+ end
132
+
133
+ context "with :all" do
134
+ should "work" do
135
+ @post.comments.find(:all).should include(@comment1)
136
+ @post.comments.find(:all).should include(@comment2)
137
+ end
138
+
139
+ should "work with conditions" do
140
+ comments = @post.comments.find(:all, :conditions => {:body => 'comment1'})
141
+ comments.should == [@comment1]
142
+ end
143
+
144
+ should "work with order" do
145
+ comments = @post.comments.find(:all, :order => 'body desc')
146
+ comments.should == [@comment2, @comment1]
147
+ end
148
+ end
149
+
150
+ context "with #all" do
151
+ should "work" do
152
+ @post.comments.all.should == [@comment1, @comment2]
153
+ end
154
+
155
+ should "work with conditions" do
156
+ comments = @post.comments.all(:conditions => {:body => 'comment1'})
157
+ comments.should == [@comment1]
158
+ end
159
+
160
+ should "work with order" do
161
+ comments = @post.comments.all(:order => '$natural desc')
162
+ comments.should == [@comment2, @comment1]
163
+ end
164
+ end
165
+
166
+ context "with one id" do
167
+ should "work for id in association" do
168
+ @post.comments.find(@comment2.id).should == @comment2
169
+ end
170
+
171
+ should "not work for id not in association" do
172
+ lambda {
173
+ @post.comments.find(@comment5.id)
174
+ }.should raise_error(MongoMapper::DocumentNotFound)
175
+ end
176
+ end
177
+
178
+ context "with multiple ids" do
179
+ should "work for ids in association" do
180
+ posts = @post.comments.find(@comment1.id, @comment2.id)
181
+ posts.should == [@comment1, @comment2]
182
+ end
183
+
184
+ should "not work for ids not in association" do
185
+ lambda {
186
+ @post.comments.find(@comment1.id, @comment2.id, @comment4.id)
187
+ }.should raise_error(MongoMapper::DocumentNotFound)
188
+ end
189
+ end
190
+
191
+ context "dynamic finders" do
192
+ should "work with single key" do
193
+ @post.comments.find_by_body('comment1').should == @comment1
194
+ @post2.comments.find_by_body('comment1').should == @comment4
195
+ end
196
+
197
+ should "work with multiple keys" do
198
+ @post.comments.find_by_body_and_name('comment1', 'John').should == @comment1
199
+ @post.comments.find_by_body_and_name('comment1', 'Frank').should be_nil
200
+ end
201
+
202
+ should "raise error when using !" do
203
+ lambda {
204
+ @post.comments.find_by_body!('asdf')
205
+ }.should raise_error(MongoMapper::DocumentNotFound)
206
+ end
207
+
208
+ context "find_or_create_by" do
209
+ should "not create document if found" do
210
+ lambda {
211
+ comment = @post.comments.find_or_create_by_name('Steve')
212
+ comment.commentable.should == @post
213
+ comment.should == @comment2
214
+ }.should_not change { PostComment.count }
215
+ end
216
+
217
+ should "create document if not found" do
218
+ lambda {
219
+ @post.comments.find_or_create_by_name('Chas')
220
+ }.should change { PostComment.count }.by(1)
221
+ end
222
+ end
223
+ end
224
+
225
+ context "with #paginate" do
226
+ setup do
227
+ @comments = @post2.comments.paginate(:per_page => 2, :page => 1, :order => 'name')
228
+ end
229
+
230
+ should "return total pages" do
231
+ @comments.total_pages.should == 2
232
+ end
233
+
234
+ should "return total entries" do
235
+ @comments.total_entries.should == 3
236
+ end
237
+
238
+ should "return the subject" do
239
+ @comments.should include(@comment4)
240
+ @comments.should include(@comment5)
241
+ end
242
+ end
243
+ end
244
+ end