djsun-mongomapper 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. data/.gitignore +7 -0
  2. data/History +51 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +39 -0
  5. data/Rakefile +71 -0
  6. data/VERSION +1 -0
  7. data/bin/mmconsole +56 -0
  8. data/lib/mongomapper.rb +96 -0
  9. data/lib/mongomapper/associations.rb +61 -0
  10. data/lib/mongomapper/associations/base.rb +71 -0
  11. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +32 -0
  12. data/lib/mongomapper/associations/belongs_to_proxy.rb +22 -0
  13. data/lib/mongomapper/associations/many_documents_proxy.rb +85 -0
  14. data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +33 -0
  15. data/lib/mongomapper/associations/many_embedded_proxy.rb +17 -0
  16. data/lib/mongomapper/associations/many_polymorphic_proxy.rb +11 -0
  17. data/lib/mongomapper/associations/many_proxy.rb +6 -0
  18. data/lib/mongomapper/associations/proxy.rb +67 -0
  19. data/lib/mongomapper/callbacks.rb +106 -0
  20. data/lib/mongomapper/document.rb +278 -0
  21. data/lib/mongomapper/embedded_document.rb +237 -0
  22. data/lib/mongomapper/finder_options.rb +96 -0
  23. data/lib/mongomapper/key.rb +80 -0
  24. data/lib/mongomapper/observing.rb +50 -0
  25. data/lib/mongomapper/pagination.rb +52 -0
  26. data/lib/mongomapper/rails_compatibility/document.rb +15 -0
  27. data/lib/mongomapper/rails_compatibility/embedded_document.rb +25 -0
  28. data/lib/mongomapper/save_with_validation.rb +19 -0
  29. data/lib/mongomapper/serialization.rb +55 -0
  30. data/lib/mongomapper/serializers/json_serializer.rb +79 -0
  31. data/lib/mongomapper/validations.rb +47 -0
  32. data/mongomapper.gemspec +139 -0
  33. data/test/NOTE_ON_TESTING +1 -0
  34. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +39 -0
  35. data/test/functional/associations/test_belongs_to_proxy.rb +35 -0
  36. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +131 -0
  37. data/test/functional/associations/test_many_embedded_proxy.rb +106 -0
  38. data/test/functional/associations/test_many_polymorphic_proxy.rb +267 -0
  39. data/test/functional/associations/test_many_proxy.rb +236 -0
  40. data/test/functional/test_associations.rb +40 -0
  41. data/test/functional/test_callbacks.rb +85 -0
  42. data/test/functional/test_document.rb +691 -0
  43. data/test/functional/test_pagination.rb +81 -0
  44. data/test/functional/test_rails_compatibility.rb +31 -0
  45. data/test/functional/test_validations.rb +172 -0
  46. data/test/models.rb +108 -0
  47. data/test/test_helper.rb +67 -0
  48. data/test/unit/serializers/test_json_serializer.rb +103 -0
  49. data/test/unit/test_association_base.rb +136 -0
  50. data/test/unit/test_document.rb +125 -0
  51. data/test/unit/test_embedded_document.rb +370 -0
  52. data/test/unit/test_finder_options.rb +214 -0
  53. data/test/unit/test_key.rb +217 -0
  54. data/test/unit/test_mongo_id.rb +35 -0
  55. data/test/unit/test_mongomapper.rb +28 -0
  56. data/test/unit/test_observing.rb +101 -0
  57. data/test/unit/test_pagination.rb +113 -0
  58. data/test/unit/test_rails_compatibility.rb +34 -0
  59. data/test/unit/test_serializations.rb +52 -0
  60. data/test/unit/test_validations.rb +259 -0
  61. metadata +189 -0
@@ -0,0 +1,81 @@
1
+ require 'test_helper'
2
+
3
+ class PaginationTest < Test::Unit::TestCase
4
+ context "Paginating" do
5
+ setup do
6
+ @document = Class.new do
7
+ include MongoMapper::Document
8
+ collection 'users'
9
+
10
+ key :first_name, String
11
+ key :last_name, String
12
+ key :age, Integer
13
+ end
14
+
15
+ @document.collection.clear
16
+
17
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
18
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
19
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
20
+ end
21
+
22
+ should "return the total pages" do
23
+ result = @document.paginate(:per_page => 2, :page => 1)
24
+ result.total_pages.should == 2
25
+ end
26
+
27
+ should "return the total of records" do
28
+ result = @document.paginate(:per_page => 2, :page => 1)
29
+ result.total_entries.should == 3
30
+ end
31
+
32
+ should "return the items" do
33
+ result = @document.paginate(:per_page => 2, :page => 1, :order => 'first_name')
34
+ result.size.should == 2
35
+ result.should == [@doc1, @doc3]
36
+ end
37
+
38
+ should "accept conditions" do
39
+ result = @document.paginate({
40
+ :conditions => {:last_name => 'Nunemaker'},
41
+ :order => "age DESC",
42
+ :per_page => 2,
43
+ :page => 1,
44
+ })
45
+ result.should == [@doc1, @doc3]
46
+ result.first.age.should == 27
47
+ end
48
+
49
+ should "withstand rigor" do
50
+ result = @document.paginate({
51
+ :per_page => 1,
52
+ :page => 1,
53
+ :order => 'age desc',
54
+ :conditions => {:last_name => 'Nunemaker'}
55
+ })
56
+ result.should == [@doc1]
57
+ result.total_entries.should == 2
58
+ result.total_pages.should == 2
59
+
60
+ result = @document.paginate({
61
+ :per_page => 1,
62
+ :page => 2,
63
+ :order => 'age desc',
64
+ :conditions => {:last_name => 'Nunemaker'}
65
+ })
66
+ result.should == [@doc3]
67
+ result.total_entries.should == 2
68
+ result.total_pages.should == 2
69
+
70
+ result = @document.paginate({
71
+ :per_page => 2,
72
+ :page => 1,
73
+ :order => 'age desc',
74
+ :conditions => {:last_name => 'Nunemaker'}
75
+ })
76
+ result.should == [@doc1, @doc3]
77
+ result.total_entries.should == 2
78
+ result.total_pages.should == 1
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,31 @@
1
+ require 'test_helper'
2
+
3
+ class TestRailsCompatibility < Test::Unit::TestCase
4
+ class Item
5
+ include MongoMapper::EmbeddedDocument
6
+ key :for_all, String
7
+ end
8
+
9
+ class Order
10
+ include MongoMapper::Document
11
+ many :items, :class_name => 'TestRailsCompatibility::Item'
12
+ key :order_only, String
13
+ end
14
+
15
+ context "Document" do
16
+ setup do
17
+ Order.collection.clear
18
+ end
19
+
20
+ should "have to_param that returns id" do
21
+ id = MongoID.new
22
+ instance = Order.create('_id' => id.to_s)
23
+ instance.to_param.should == id.to_s
24
+ end
25
+
26
+ should "alias new to new_record?" do
27
+ instance = Order.new
28
+ instance.new_record?.should == instance.new?
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,172 @@
1
+ require 'test_helper'
2
+
3
+ class ValidationsTest < Test::Unit::TestCase
4
+ context "Saving a new document that is invalid" do
5
+ setup do
6
+ @document = Class.new do
7
+ include MongoMapper::Document
8
+ key :name, String, :required => true
9
+ end
10
+ @document.collection.clear
11
+ end
12
+
13
+ should "not insert document" do
14
+ doc = @document.new
15
+ doc.save
16
+ @document.count.should == 0
17
+ end
18
+
19
+ should "populate document's errors" do
20
+ doc = @document.new
21
+ doc.errors.size.should == 0
22
+ doc.save
23
+ doc.errors.full_messages.should == ["Name can't be empty"]
24
+ end
25
+ end
26
+
27
+ context "Saving a document that is invalid (destructive)" do
28
+ setup do
29
+ @document = Class.new do
30
+ include MongoMapper::Document
31
+ key :name, String, :required => true
32
+ end
33
+ @document.collection.clear
34
+ end
35
+
36
+ should "raise error" do
37
+ doc = @document.new
38
+ lambda { doc.save! }.should raise_error(MongoMapper::DocumentNotValid)
39
+ end
40
+ end
41
+
42
+ context "Saving an existing document that is invalid" do
43
+ setup do
44
+ @document = Class.new do
45
+ include MongoMapper::Document
46
+ key :name, String, :required => true
47
+ end
48
+ @document.collection.clear
49
+
50
+ @doc = @document.create(:name => 'John Nunemaker')
51
+ end
52
+
53
+ should "not update document" do
54
+ @doc.name = nil
55
+ @doc.save
56
+ @document.find(@doc.id).name.should == 'John Nunemaker'
57
+ end
58
+
59
+ should "populate document's errors" do
60
+ @doc.name = nil
61
+ @doc.save
62
+ @doc.errors.full_messages.should == ["Name can't be empty"]
63
+ end
64
+ end
65
+
66
+ context "Adding validation errors" do
67
+ setup do
68
+ @document = Class.new do
69
+ include MongoMapper::Document
70
+ key :action, String
71
+ def action_present
72
+ errors.add(:action, 'is invalid') if action.blank?
73
+ end
74
+ end
75
+ @document.collection.clear
76
+ end
77
+
78
+ should "work with validate_on_create callback" do
79
+ @document.validate_on_create :action_present
80
+
81
+ doc = @document.new
82
+ doc.action = nil
83
+ doc.should have_error_on(:action)
84
+
85
+ doc.action = 'kick'
86
+ doc.should_not have_error_on(:action)
87
+ doc.save
88
+
89
+ doc.action = nil
90
+ doc.should_not have_error_on(:action)
91
+ end
92
+
93
+ should "work with validate_on_update callback" do
94
+ @document.validate_on_update :action_present
95
+
96
+ doc = @document.new
97
+ doc.action = nil
98
+ doc.should_not have_error_on(:action)
99
+ doc.save
100
+
101
+ doc.action = nil
102
+ doc.should have_error_on(:action)
103
+
104
+ doc.action = 'kick'
105
+ doc.should_not have_error_on(:action)
106
+ end
107
+ end
108
+
109
+ context "validating uniqueness of" do
110
+ setup do
111
+ @document = Class.new do
112
+ include MongoMapper::Document
113
+ key :name, String
114
+ validates_uniqueness_of :name
115
+ end
116
+ @document.collection.clear
117
+ end
118
+
119
+ should "not fail if object is new" do
120
+ doc = @document.new
121
+ doc.should_not have_error_on(:name)
122
+ end
123
+
124
+ should "allow to update an object" do
125
+ doc = @document.new("name" => "joe")
126
+ doc.save.should be_true
127
+
128
+ @document \
129
+ .stubs(:find) \
130
+ .with(:first, :conditions => {:name => 'joe'}, :limit => 1) \
131
+ .returns(doc)
132
+
133
+ doc.name = "joe"
134
+ doc.valid?.should be_true
135
+ doc.should_not have_error_on(:name)
136
+ end
137
+
138
+ should "fail if object name is not unique" do
139
+ doc = @document.new("name" => "joe")
140
+ doc.save.should be_true
141
+
142
+ @document \
143
+ .stubs(:find) \
144
+ .with(:first, :conditions => {:name => 'joe'}, :limit => 1) \
145
+ .returns(doc)
146
+
147
+ doc2 = @document.new("name" => "joe")
148
+ doc2.should have_error_on(:name)
149
+ end
150
+ end
151
+
152
+ context "validates uniqueness of with :unique shortcut" do
153
+ should "work" do
154
+ @document = Class.new do
155
+ include MongoMapper::Document
156
+ key :name, String, :unique => true
157
+ end
158
+ @document.collection.clear
159
+
160
+ doc = @document.create(:name => 'John')
161
+ doc.should_not have_error_on(:name)
162
+
163
+ @document \
164
+ .stubs(:find) \
165
+ .with(:first, :conditions => {:name => 'John'}, :limit => 1) \
166
+ .returns(doc)
167
+
168
+ second_john = @document.create(:name => 'John')
169
+ second_john.should have_error_on(:name, 'has already been taken')
170
+ end
171
+ end
172
+ end
data/test/models.rb ADDED
@@ -0,0 +1,108 @@
1
+ class Address
2
+ include MongoMapper::EmbeddedDocument
3
+ key :address, String
4
+ key :city, String
5
+ key :state, String
6
+ key :zip, Integer
7
+ end
8
+
9
+ class Message
10
+ include MongoMapper::Document
11
+ key :body, String
12
+ belongs_to :room
13
+ end
14
+
15
+ class Enter < Message; end
16
+ class Exit < Message; end
17
+ class Chat < Message; end
18
+
19
+ class Room
20
+ include MongoMapper::Document
21
+ key :name, String
22
+ many :messages, :polymorphic => true
23
+ end
24
+
25
+ class Project
26
+ include MongoMapper::Document
27
+ key :name, String
28
+ many :statuses
29
+ many :addresses
30
+ end
31
+
32
+ class Status
33
+ include MongoMapper::Document
34
+ belongs_to :project
35
+ belongs_to :target, :polymorphic => true
36
+ key :name, String
37
+ end
38
+
39
+ class RealPerson
40
+ include MongoMapper::Document
41
+ many :pets
42
+ key :name, String
43
+ end
44
+
45
+ class Person
46
+ include MongoMapper::EmbeddedDocument
47
+ key :name, String
48
+ key :child, Person
49
+ many :pets
50
+ end
51
+
52
+ class Pet
53
+ include MongoMapper::EmbeddedDocument
54
+ key :name, String
55
+ key :species, String
56
+ end
57
+
58
+ class Media
59
+ include MongoMapper::EmbeddedDocument
60
+ key :file, String
61
+ end
62
+
63
+ class Video < Media
64
+ key :length, Integer
65
+ end
66
+
67
+ class Image < Media
68
+ key :width, Integer
69
+ key :height, Integer
70
+ end
71
+
72
+ class Music < Media
73
+ key :bitrate, String
74
+ end
75
+
76
+ class Catalog
77
+ include MongoMapper::Document
78
+ many :medias, :polymorphic => true
79
+ end
80
+
81
+ module TrModels
82
+ class Transport
83
+ include MongoMapper::EmbeddedDocument
84
+ key :license_plate, String
85
+ end
86
+
87
+ class Car < TrModels::Transport
88
+ include MongoMapper::EmbeddedDocument
89
+ key :model, String
90
+ key :year, Integer
91
+ end
92
+
93
+ class Bus < TrModels::Transport
94
+ include MongoMapper::EmbeddedDocument
95
+ key :max_passengers, Integer
96
+ end
97
+
98
+ class Ambulance < TrModels::Transport
99
+ include MongoMapper::EmbeddedDocument
100
+ key :icu, Boolean
101
+ end
102
+
103
+ class Fleet
104
+ include MongoMapper::Document
105
+ many :transports, :polymorphic => true, :class_name => "TrModels::Transport"
106
+ key :name, String
107
+ end
108
+ end
@@ -0,0 +1,67 @@
1
+ require 'pathname'
2
+ require 'pp'
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'shoulda'
6
+
7
+ gem 'mocha', '0.9.4'
8
+ gem 'jnunemaker-matchy', '0.4.0'
9
+
10
+ require 'matchy'
11
+ require 'mocha'
12
+
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+ dir = (Pathname(__FILE__).dirname + '..' + 'lib').expand_path
15
+ require dir + 'mongomapper'
16
+
17
+ class Test::Unit::TestCase
18
+ def clear_all_collections
19
+ MongoMapper::Document.descendants.map(&:delete_all)
20
+ end
21
+
22
+ custom_matcher :be_nil do |receiver, matcher, args|
23
+ matcher.positive_failure_message = "Expected #{receiver} to be nil but it wasn't"
24
+ matcher.negative_failure_message = "Expected #{receiver} not to be nil but it was"
25
+ receiver.nil?
26
+ end
27
+
28
+ custom_matcher :be_true do |receiver, matcher, args|
29
+ matcher.positive_failure_message = "Expected #{receiver} to be true but it wasn't"
30
+ matcher.negative_failure_message = "Expected #{receiver} not to be true but it was"
31
+ receiver.eql?(true)
32
+ end
33
+
34
+ custom_matcher :be_false do |receiver, matcher, args|
35
+ matcher.positive_failure_message = "Expected #{receiver} to be false but it wasn't"
36
+ matcher.negative_failure_message = "Expected #{receiver} not to be false but it was"
37
+ receiver.eql?(false)
38
+ end
39
+
40
+ custom_matcher :be_valid do |receiver, matcher, args|
41
+ matcher.positive_failure_message = "Expected to be valid but it was invalid #{receiver.errors.inspect}"
42
+ matcher.negative_failure_message = "Expected to be invalid but it was valid #{receiver.errors.inspect}"
43
+ receiver.valid?
44
+ end
45
+
46
+ custom_matcher :have_error_on do |receiver, matcher, args|
47
+ receiver.valid?
48
+ attribute = args[0]
49
+ expected_message = args[1]
50
+
51
+ if expected_message.nil?
52
+ matcher.positive_failure_message = "#{receiver} had no errors on #{attribute}"
53
+ matcher.negative_failure_message = "#{receiver} had errors on #{attribute} #{receiver.errors.inspect}"
54
+ !receiver.errors.on(attribute).blank?
55
+ else
56
+ actual = receiver.errors.on(attribute)
57
+ matcher.positive_failure_message = %Q(Expected error on #{attribute} to be "#{expected_message}" but was "#{actual}")
58
+ matcher.negative_failure_message = %Q(Expected error on #{attribute} not to be "#{expected_message}" but was "#{actual}")
59
+ actual == expected_message
60
+ end
61
+ end
62
+ end
63
+
64
+ DefaultDatabase = 'test' unless defined?(DefaultDatabase)
65
+ AlternateDatabase = 'test2' unless defined?(AlternateDatabase)
66
+
67
+ MongoMapper.database = DefaultDatabase