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.
Files changed (55) hide show
  1. data/.gitignore +1 -0
  2. data/History +17 -0
  3. data/README.rdoc +6 -3
  4. data/Rakefile +3 -2
  5. data/VERSION +1 -1
  6. data/bin/mmconsole +56 -0
  7. data/lib/mongomapper.rb +48 -17
  8. data/lib/mongomapper/associations.rb +31 -39
  9. data/lib/mongomapper/associations/base.rb +40 -22
  10. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +33 -0
  11. data/lib/mongomapper/associations/belongs_to_proxy.rb +10 -14
  12. data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +34 -0
  13. data/lib/mongomapper/associations/{has_many_embedded_proxy.rb → many_embedded_proxy.rb} +5 -5
  14. data/lib/mongomapper/associations/many_proxy.rb +55 -0
  15. data/lib/mongomapper/associations/proxy.rb +21 -14
  16. data/lib/mongomapper/callbacks.rb +1 -1
  17. data/lib/mongomapper/document.rb +82 -59
  18. data/lib/mongomapper/embedded_document.rb +121 -130
  19. data/lib/mongomapper/finder_options.rb +21 -6
  20. data/lib/mongomapper/key.rb +5 -7
  21. data/lib/mongomapper/observing.rb +1 -41
  22. data/lib/mongomapper/pagination.rb +52 -0
  23. data/lib/mongomapper/rails_compatibility/document.rb +15 -0
  24. data/lib/mongomapper/rails_compatibility/embedded_document.rb +25 -0
  25. data/lib/mongomapper/serialization.rb +1 -1
  26. data/mongomapper.gemspec +62 -36
  27. data/test/NOTE_ON_TESTING +1 -0
  28. data/test/functional/test_associations.rb +485 -0
  29. data/test/{test_callbacks.rb → functional/test_callbacks.rb} +2 -1
  30. data/test/functional/test_document.rb +636 -0
  31. data/test/functional/test_pagination.rb +82 -0
  32. data/test/functional/test_rails_compatibility.rb +31 -0
  33. data/test/functional/test_validations.rb +172 -0
  34. data/test/models.rb +92 -0
  35. data/test/test_helper.rb +5 -0
  36. data/test/{serializers → unit/serializers}/test_json_serializer.rb +0 -0
  37. data/test/unit/test_association_base.rb +131 -0
  38. data/test/unit/test_document.rb +115 -0
  39. data/test/{test_embedded_document.rb → unit/test_embedded_document.rb} +158 -66
  40. data/test/{test_finder_options.rb → unit/test_finder_options.rb} +66 -0
  41. data/test/{test_key.rb → unit/test_key.rb} +13 -1
  42. data/test/unit/test_mongo_id.rb +35 -0
  43. data/test/{test_mongomapper.rb → unit/test_mongomapper.rb} +0 -0
  44. data/test/{test_observing.rb → unit/test_observing.rb} +0 -0
  45. data/test/unit/test_pagination.rb +113 -0
  46. data/test/unit/test_rails_compatibility.rb +34 -0
  47. data/test/{test_serializations.rb → unit/test_serializations.rb} +0 -2
  48. data/test/{test_validations.rb → unit/test_validations.rb} +0 -134
  49. metadata +68 -36
  50. data/lib/mongomapper/associations/has_many_proxy.rb +0 -28
  51. data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +0 -31
  52. data/lib/mongomapper/rails_compatibility.rb +0 -23
  53. data/test/test_associations.rb +0 -149
  54. data/test/test_document.rb +0 -944
  55. data/test/test_rails_compatibility.rb +0 -29
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jnunemaker-mongomapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
@@ -9,8 +9,8 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-07 00:00:00 -07:00
13
- default_executable:
12
+ date: 2009-07-28 00:00:00 -07:00
13
+ default_executable: mmconsole
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - "="
32
32
  - !ruby/object:Gem::Version
33
- version: "0.9"
33
+ version: 0.10.1
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: jnunemaker-validatable
@@ -40,7 +40,17 @@ dependencies:
40
40
  requirements:
41
41
  - - "="
42
42
  - !ruby/object:Gem::Version
43
- version: 1.7.1
43
+ version: 1.7.2
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: deep_merge
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.1.0
44
54
  version:
45
55
  - !ruby/object:Gem::Dependency
46
56
  name: mocha
@@ -64,8 +74,8 @@ dependencies:
64
74
  version:
65
75
  description:
66
76
  email: nunemaker@gmail.com
67
- executables: []
68
-
77
+ executables:
78
+ - mmconsole
69
79
  extensions: []
70
80
 
71
81
  extra_rdoc_files:
@@ -78,14 +88,16 @@ files:
78
88
  - README.rdoc
79
89
  - Rakefile
80
90
  - VERSION
91
+ - bin/mmconsole
81
92
  - lib/mongomapper.rb
82
93
  - lib/mongomapper/associations.rb
83
94
  - lib/mongomapper/associations/array_proxy.rb
84
95
  - lib/mongomapper/associations/base.rb
96
+ - lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb
85
97
  - lib/mongomapper/associations/belongs_to_proxy.rb
86
- - lib/mongomapper/associations/has_many_embedded_proxy.rb
87
- - lib/mongomapper/associations/has_many_proxy.rb
88
- - lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb
98
+ - lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb
99
+ - lib/mongomapper/associations/many_embedded_proxy.rb
100
+ - lib/mongomapper/associations/many_proxy.rb
89
101
  - lib/mongomapper/associations/proxy.rb
90
102
  - lib/mongomapper/callbacks.rb
91
103
  - lib/mongomapper/document.rb
@@ -93,27 +105,39 @@ files:
93
105
  - lib/mongomapper/finder_options.rb
94
106
  - lib/mongomapper/key.rb
95
107
  - lib/mongomapper/observing.rb
96
- - lib/mongomapper/rails_compatibility.rb
108
+ - lib/mongomapper/pagination.rb
109
+ - lib/mongomapper/rails_compatibility/document.rb
110
+ - lib/mongomapper/rails_compatibility/embedded_document.rb
97
111
  - lib/mongomapper/save_with_validation.rb
98
112
  - lib/mongomapper/serialization.rb
99
113
  - lib/mongomapper/serializers/json_serializer.rb
100
114
  - lib/mongomapper/validations.rb
101
115
  - mongomapper.gemspec
102
- - test/serializers/test_json_serializer.rb
103
- - test/test_associations.rb
104
- - test/test_callbacks.rb
105
- - test/test_document.rb
106
- - test/test_embedded_document.rb
107
- - test/test_finder_options.rb
116
+ - test/NOTE_ON_TESTING
117
+ - test/functional/test_associations.rb
118
+ - test/functional/test_callbacks.rb
119
+ - test/functional/test_document.rb
120
+ - test/functional/test_pagination.rb
121
+ - test/functional/test_rails_compatibility.rb
122
+ - test/functional/test_validations.rb
123
+ - test/models.rb
108
124
  - test/test_helper.rb
109
- - test/test_key.rb
110
- - test/test_mongomapper.rb
111
- - test/test_observing.rb
112
- - test/test_rails_compatibility.rb
113
- - test/test_serializations.rb
114
- - test/test_validations.rb
125
+ - test/unit/serializers/test_json_serializer.rb
126
+ - test/unit/test_association_base.rb
127
+ - test/unit/test_document.rb
128
+ - test/unit/test_embedded_document.rb
129
+ - test/unit/test_finder_options.rb
130
+ - test/unit/test_key.rb
131
+ - test/unit/test_mongo_id.rb
132
+ - test/unit/test_mongomapper.rb
133
+ - test/unit/test_observing.rb
134
+ - test/unit/test_pagination.rb
135
+ - test/unit/test_rails_compatibility.rb
136
+ - test/unit/test_serializations.rb
137
+ - test/unit/test_validations.rb
115
138
  has_rdoc: true
116
139
  homepage: http://github.com/jnunemaker/mongomapper
140
+ licenses:
117
141
  post_install_message:
118
142
  rdoc_options:
119
143
  - --charset=UTF-8
@@ -134,21 +158,29 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
158
  requirements: []
135
159
 
136
160
  rubyforge_project: mongomapper
137
- rubygems_version: 1.2.0
161
+ rubygems_version: 1.3.5
138
162
  signing_key:
139
163
  specification_version: 2
140
164
  summary: Awesome gem for modeling your domain and storing it in mongo
141
165
  test_files:
142
- - test/serializers/test_json_serializer.rb
143
- - test/test_associations.rb
144
- - test/test_callbacks.rb
145
- - test/test_document.rb
146
- - test/test_embedded_document.rb
147
- - test/test_finder_options.rb
166
+ - test/functional/test_associations.rb
167
+ - test/functional/test_callbacks.rb
168
+ - test/functional/test_document.rb
169
+ - test/functional/test_pagination.rb
170
+ - test/functional/test_rails_compatibility.rb
171
+ - test/functional/test_validations.rb
172
+ - test/models.rb
148
173
  - test/test_helper.rb
149
- - test/test_key.rb
150
- - test/test_mongomapper.rb
151
- - test/test_observing.rb
152
- - test/test_rails_compatibility.rb
153
- - test/test_serializations.rb
154
- - test/test_validations.rb
174
+ - test/unit/serializers/test_json_serializer.rb
175
+ - test/unit/test_association_base.rb
176
+ - test/unit/test_document.rb
177
+ - test/unit/test_embedded_document.rb
178
+ - test/unit/test_finder_options.rb
179
+ - test/unit/test_key.rb
180
+ - test/unit/test_mongo_id.rb
181
+ - test/unit/test_mongomapper.rb
182
+ - test/unit/test_observing.rb
183
+ - test/unit/test_pagination.rb
184
+ - test/unit/test_rails_compatibility.rb
185
+ - test/unit/test_serializations.rb
186
+ - test/unit/test_validations.rb
@@ -1,28 +0,0 @@
1
- module MongoMapper
2
- module Associations
3
- class HasManyProxy < ArrayProxy
4
- def replace(v)
5
- if load_target
6
- @target.map(&:destroy)
7
- end
8
-
9
- v.each do |o|
10
- @owner.save if @owner.new?
11
- o.__send__(:write_attribute, self.foreign_key, @owner.id)
12
- o.save
13
- o
14
- end
15
- reload_target
16
- end
17
-
18
- protected
19
- def find_target
20
- @association.klass.find(:all, {:conditions => {self.foreign_key => @owner.id}})
21
- end
22
-
23
- def foreign_key
24
- @association.options[:foreign_key] || @owner.class.name.underscore.gsub("/", "_") + "_id"
25
- end
26
- end
27
- end
28
- end
@@ -1,31 +0,0 @@
1
- module MongoMapper
2
- module Associations
3
- class PolymorphicBelongsToProxy < Proxy
4
- def replace(v)
5
- ref_id = "#{@association.name}_id"
6
- ref_type = "#{@association.name}_type"
7
-
8
- if v
9
- v.save if v.new?
10
- @owner.__send__(:write_attribute, ref_id, v.id)
11
- @owner.__send__(:write_attribute, ref_type, v.class.name)
12
- else
13
- @owner.__send__(:write_attribute, ref_id, nil)
14
- @owner.__send__(:write_attribute, ref_type, nil)
15
- end
16
- @owner.save
17
-
18
- reload_target
19
- end
20
-
21
- protected
22
- def find_target
23
- ref_id = @owner.__send__(:read_attribute, "#{@association.name}_id")
24
- ref_type = @owner.__send__(:read_attribute, "#{@association.name}_type")
25
- if ref_id && ref_type
26
- ref_type.constantize.find(ref_id)
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,23 +0,0 @@
1
- module MongoMapper
2
- module RailsCompatibility
3
- def self.included(model)
4
- model.class_eval do
5
- alias_method :new_record?, :new?
6
- extend ClassMethods
7
- end
8
- class << model
9
- alias_method :has_many, :many
10
- end
11
- end
12
-
13
- module ClassMethods
14
- def column_names
15
- keys.keys
16
- end
17
- end
18
-
19
- def to_param
20
- id
21
- end
22
- end
23
- end
@@ -1,149 +0,0 @@
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 Project
13
- include MongoMapper::Document
14
-
15
- key :name, String
16
-
17
- many :statuses
18
- many :addresses
19
- end
20
-
21
- class Status
22
- include MongoMapper::Document
23
-
24
- belongs_to :project
25
- belongs_to :target, :polymorphic => true
26
-
27
- key :name, String
28
- end
29
-
30
- class AssociationsTest < Test::Unit::TestCase
31
- def setup
32
- Project.collection.clear
33
- Status.collection.clear
34
- end
35
-
36
- context "Polymorphic Belongs To" do
37
- should "default to nil" do
38
- status = Status.new
39
- status.target.should be_nil
40
- end
41
-
42
- should "store the association" do
43
- status = Status.new
44
- project = Project.new(:name => "mongomapper")
45
- status.target = project
46
- status.save.should be_true
47
-
48
- from_db = Status.find(status.id)
49
- from_db.target.should_not be_nil
50
- from_db.target_id.should == project.id
51
- from_db.target_type.should == "Project"
52
- from_db.target.name.should == "mongomapper"
53
- end
54
-
55
- should "unset the association" do
56
- status = Status.new
57
- project = Project.new(:name => "mongomapper")
58
- status.target = project
59
- status.save.should be_true
60
-
61
- from_db = Status.find(status.id)
62
- from_db.target = nil
63
- from_db.target_type.should be_nil
64
- from_db.target_id.should be_nil
65
- from_db.target.should be_nil
66
- end
67
- end
68
-
69
- context "Belongs To" do
70
- should "default to nil" do
71
- status = Status.new
72
- status.project.should be_nil
73
- end
74
-
75
- should "store the association" do
76
- status = Status.new
77
- project = Project.new(:name => "mongomapper")
78
- status.project = project
79
- status.save.should be_true
80
-
81
- from_db = Status.find(status.id)
82
- from_db.project.should_not be_nil
83
- from_db.project.name.should == "mongomapper"
84
- end
85
-
86
- should "unset the association" do
87
- status = Status.new
88
- project = Project.new(:name => "mongomapper")
89
- status.project = project
90
- status.save.should be_true
91
-
92
- from_db = Status.find(status.id)
93
- from_db.project = nil
94
- from_db.project.should be_nil
95
- end
96
- end
97
-
98
- context "Many documents" do
99
- should "default reader to empty array" do
100
- project = Project.new
101
- project.statuses.should == []
102
- end
103
-
104
- should "allow adding to association like it was an array" do
105
- project = Project.new
106
- project.statuses << Status.new
107
- project.statuses.push Status.new
108
- project.statuses.size.should == 2
109
- end
110
-
111
- should "store the association" do
112
- project = Project.new
113
- project.statuses = [Status.new("name" => "ready")]
114
- project.save.should be_true
115
-
116
- from_db = Project.find(project.id)
117
- from_db.statuses.size.should == 1
118
- from_db.statuses[0].name.should == "ready"
119
- end
120
- end
121
-
122
- context "Many embedded documents" do
123
- should "default reader to empty array" do
124
- project = Project.new
125
- project.addresses.should == []
126
- end
127
-
128
- should "allow adding to association like it was an array" do
129
- project = Project.new
130
- project.addresses << Address.new
131
- project.addresses.push Address.new
132
- project.addresses.size.should == 2
133
- end
134
-
135
- should "be embedded in document on save" do
136
- sb = Address.new(:city => 'South Bend', :state => 'IN')
137
- chi = Address.new(:city => 'Chicago', :state => 'IL')
138
- project = Project.new
139
- project.addresses << sb
140
- project.addresses << chi
141
- project.save
142
-
143
- from_db = Project.find(project.id)
144
- from_db.addresses.size.should == 2
145
- from_db.addresses[0].should == sb
146
- from_db.addresses[1].should == chi
147
- end
148
- end
149
- end
@@ -1,944 +0,0 @@
1
- require 'test_helper'
2
-
3
- class Address
4
- include MongoMapper::EmbeddedDocument
5
- key :city, String
6
- key :state, String
7
- end
8
-
9
- class DocumentTest < Test::Unit::TestCase
10
- context "The Document Class" do
11
- setup do
12
- @document = Class.new do
13
- include MongoMapper::Document
14
- end
15
- end
16
-
17
- should "track its descendants" do
18
- MongoMapper::Document.descendants.should include(@document)
19
- end
20
-
21
- should "be able to define a key" do
22
- key = @document.key(:name, String)
23
- key.name.should == 'name'
24
- key.type.should == String
25
- key.should be_instance_of(MongoMapper::Key)
26
- end
27
-
28
- should "be able to define a key with options" do
29
- key = @document.key(:name, String, :required => true)
30
- key.options[:required].should be(true)
31
- end
32
-
33
- should "know what keys have been defined" do
34
- @document.key(:name, String)
35
- @document.key(:age, Integer)
36
- @document.keys['name'].name.should == 'name'
37
- @document.keys['name'].type.should == String
38
- @document.keys['age'].name.should == 'age'
39
- @document.keys['age'].type.should == Integer
40
- end
41
-
42
- should "use default database by default" do
43
- @document.database.should == MongoMapper.database
44
- end
45
-
46
- should "have a connection" do
47
- @document.connection.should be_instance_of(XGen::Mongo::Driver::Mongo)
48
- end
49
-
50
- should "allow setting different connection without affecting the default" do
51
- conn = XGen::Mongo::Driver::Mongo.new
52
- @document.connection conn
53
- @document.connection.should == conn
54
- @document.connection.should_not == MongoMapper.connection
55
- end
56
-
57
- should "allow setting a different database without affecting the default" do
58
- @document.database AlternateDatabase
59
- @document.database.name.should == AlternateDatabase
60
-
61
- another_document = Class.new do
62
- include MongoMapper::Document
63
- end
64
- another_document.database.should == MongoMapper.database
65
- end
66
-
67
- class Item; include MongoMapper::Document; end
68
- should "default collection name to class name tableized" do
69
- Item.collection.should be_instance_of(XGen::Mongo::Driver::Collection)
70
- Item.collection.name.should == 'items'
71
- end
72
-
73
- should "allow setting the collection name" do
74
- @document.collection('foobar')
75
- @document.collection.should be_instance_of(XGen::Mongo::Driver::Collection)
76
- @document.collection.name.should == 'foobar'
77
- end
78
- end # Document class
79
-
80
- context "Database operations" do
81
- setup do
82
- @document = Class.new do
83
- include MongoMapper::Document
84
- collection 'users'
85
-
86
- key :fname, String
87
- key :lname, String
88
- key :age, Integer
89
- end
90
-
91
- @document.collection.clear
92
- end
93
-
94
- context "Using key with type Array" do
95
- setup do
96
- @document.key :tags, Array
97
- end
98
-
99
- should "work" do
100
- doc = @document.new
101
- doc.tags.should == []
102
- doc.tags = %w(foo bar)
103
- doc.save
104
- doc.tags.should == %w(foo bar)
105
- @document.find(doc.id).tags.should == %w(foo bar)
106
- end
107
- end
108
-
109
- context "Using key with type Hash" do
110
- setup do
111
- @document.key :foo, Hash
112
- end
113
-
114
- should "work with indifferent access" do
115
- doc = @document.new
116
- doc.foo = {:baz => 'bar'}
117
- doc.save
118
-
119
- doc = @document.find(doc.id)
120
- doc.foo[:baz].should == 'bar'
121
- doc.foo['baz'].should == 'bar'
122
- end
123
- end
124
-
125
- context "Saving a document with an embedded document" do
126
- setup do
127
- @document.class_eval do
128
- key :foo, Address
129
- end
130
- end
131
-
132
- should "embed embedded document" do
133
- address = Address.new(:city => 'South Bend', :state => 'IN')
134
- doc = @document.new(:foo => address)
135
- doc.save
136
- doc.foo.city.should == 'South Bend'
137
- doc.foo.state.should == 'IN'
138
-
139
- from_db = @document.find(doc.id)
140
- from_db.foo.city.should == 'South Bend'
141
- from_db.foo.state.should == 'IN'
142
- end
143
- end
144
-
145
- context "Creating a single document" do
146
- setup do
147
- @doc_instance = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
148
- end
149
-
150
- should "create a document in correct collection" do
151
- @document.count.should == 1
152
- end
153
-
154
- should "automatically set id" do
155
- @doc_instance.id.should_not be_nil
156
- @doc_instance.id.size.should == 24
157
- end
158
-
159
- should "return instance of document" do
160
- @doc_instance.should be_instance_of(@document)
161
- @doc_instance.fname.should == 'John'
162
- @doc_instance.lname.should == 'Nunemaker'
163
- @doc_instance.age.should == 27
164
- end
165
- end
166
-
167
- context "Creating multiple documents" do
168
- setup do
169
- @doc_instances = @document.create([
170
- {:fname => 'John', :lname => 'Nunemaker', :age => '27'},
171
- {:fname => 'Steve', :lname => 'Smith', :age => '28'},
172
- ])
173
- end
174
-
175
- should "create multiple documents" do
176
- @document.count.should == 2
177
- end
178
-
179
- should "return an array of doc instances" do
180
- @doc_instances.map do |doc_instance|
181
- doc_instance.should be_instance_of(@document)
182
- end
183
- end
184
- end
185
-
186
- context "Updating a document" do
187
- setup do
188
- doc = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
189
- @doc_instance = @document.update(doc.id, {:age => 40})
190
- end
191
-
192
- should "update attributes provided" do
193
- @doc_instance.age.should == 40
194
- end
195
-
196
- should "not update existing attributes that were not set to update" do
197
- @doc_instance.fname.should == 'John'
198
- @doc_instance.lname.should == 'Nunemaker'
199
- end
200
-
201
- should "not create new document" do
202
- @document.count.should == 1
203
- end
204
- end
205
-
206
- should "raise error when updating single doc if not provided id and attributes" do
207
- doc = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
208
- lambda { @document.update }.should raise_error(ArgumentError)
209
- lambda { @document.update(doc.id) }.should raise_error(ArgumentError)
210
- lambda { @document.update(doc.id, [1]) }.should raise_error(ArgumentError)
211
- end
212
-
213
- context "Updating multiple documents" do
214
- setup do
215
- @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
216
- @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
217
-
218
- @doc_instances = @document.update({
219
- @doc1.id => {:age => 30},
220
- @doc2.id => {:age => 30},
221
- })
222
- end
223
-
224
- should "not create any new documents" do
225
- @document.count.should == 2
226
- end
227
-
228
- should "should return an array of doc instances" do
229
- @doc_instances.map do |doc_instance|
230
- doc_instance.should be_instance_of(@document)
231
- end
232
- end
233
-
234
- should "update the documents" do
235
- @document.find(@doc1.id).age.should == 30
236
- @document.find(@doc2.id).age.should == 30
237
- end
238
- end
239
-
240
- should "raise error when updating multiple documents if not a hash" do
241
- lambda { @document.update([1, 2]) }.should raise_error(ArgumentError)
242
- end
243
-
244
- context "Finding documents" do
245
- setup do
246
- @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
247
- @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
248
- @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
249
- end
250
-
251
- should "raise document not found if nothing provided" do
252
- lambda { @document.find }.should raise_error(MongoMapper::DocumentNotFound)
253
- end
254
-
255
- context "with a single id" do
256
- should "work" do
257
- @document.find(@doc1.id).should == @doc1
258
- end
259
-
260
- should "raise error if document not found" do
261
- lambda { @document.find(1) }.should raise_error(MongoMapper::DocumentNotFound)
262
- end
263
- end
264
-
265
- context "with multiple id's" do
266
- should "work as arguments" do
267
- @document.find(@doc1.id, @doc2.id).should == [@doc1, @doc2]
268
- end
269
-
270
- should "work as array" do
271
- @document.find([@doc1.id, @doc2.id]).should == [@doc1, @doc2]
272
- end
273
- end
274
-
275
- context "with :all" do
276
- should "find all documents" do
277
- @document.find(:all).should == [@doc1, @doc2, @doc3]
278
- end
279
-
280
- should "be able to add conditions" do
281
- @document.find(:all, :conditions => {:fname => 'John'}).should == [@doc1]
282
- end
283
- end
284
-
285
- context "with #all" do
286
- should "find all documents based on criteria" do
287
- @document.all.should == [@doc1, @doc2, @doc3]
288
- @document.all(:conditions => {:lname => 'Nunemaker'}).should == [@doc1, @doc3]
289
- end
290
- end
291
-
292
- context "with :first" do
293
- should "find first document" do
294
- @document.find(:first).should == @doc1
295
- end
296
- end
297
-
298
- context "with #first" do
299
- should "find first document based on criteria" do
300
- @document.first.should == @doc1
301
- @document.first(:conditions => {:age => 28}).should == @doc2
302
- end
303
- end
304
-
305
- context "with :last" do
306
- should "find last document" do
307
- @document.find(:last).should == @doc3
308
- end
309
- end
310
-
311
- context "with #last" do
312
- should "find last document based on criteria" do
313
- @document.last.should == @doc3
314
- @document.last(:conditions => {:age => 28}).should == @doc2
315
- end
316
- end
317
- end # finding documents
318
-
319
- context "Finding document by id" do
320
- setup do
321
- @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
322
- @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
323
- end
324
-
325
- should "be able to find by id" do
326
- @document.find_by_id(@doc1.id).should == @doc1
327
- @document.find_by_id(@doc2.id).should == @doc2
328
- end
329
-
330
- should "return nil if document not found" do
331
- @document.find_by_id(1234).should be(nil)
332
- end
333
- end
334
-
335
- context "Deleting a document" do
336
- setup do
337
- @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
338
- @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
339
- @document.delete(@doc1.id)
340
- end
341
-
342
- should "remove document from collection" do
343
- @document.count.should == 1
344
- end
345
-
346
- should "not remove other documents" do
347
- @document.find(@doc2.id).should_not be(nil)
348
- end
349
- end
350
-
351
- context "Deleting multiple documents" do
352
- should "work with multiple arguments" do
353
- @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
354
- @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
355
- @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
356
- @document.delete(@doc1.id, @doc2.id)
357
-
358
- @document.count.should == 1
359
- end
360
-
361
- should "work with array as argument" do
362
- @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
363
- @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
364
- @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
365
- @document.delete([@doc1.id, @doc2.id])
366
-
367
- @document.count.should == 1
368
- end
369
- end
370
-
371
- context "Deleting all documents" do
372
- setup do
373
- @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
374
- @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
375
- @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
376
- end
377
-
378
- should "remove all documents when given no conditions" do
379
- @document.delete_all
380
- @document.count.should == 0
381
- end
382
-
383
- should "only remove matching documents when given conditions" do
384
- @document.delete_all({:fname => 'John'})
385
- @document.count.should == 2
386
- end
387
-
388
- should "convert the conditions to mongo criteria" do
389
- @document.delete_all(:age => [26, 27])
390
- @document.count.should == 1
391
- end
392
- end
393
-
394
- context "Destroying a document" do
395
- setup do
396
- @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
397
- @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
398
- @document.destroy(@doc1.id)
399
- end
400
-
401
- should "remove document from collection" do
402
- @document.count.should == 1
403
- end
404
-
405
- should "not remove other documents" do
406
- @document.find(@doc2.id).should_not be(nil)
407
- end
408
- end
409
-
410
- context "Destroying multiple documents" do
411
- should "work with multiple arguments" do
412
- @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
413
- @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
414
- @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
415
- @document.destroy(@doc1.id, @doc2.id)
416
-
417
- @document.count.should == 1
418
- end
419
-
420
- should "work with array as argument" do
421
- @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
422
- @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
423
- @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
424
- @document.destroy([@doc1.id, @doc2.id])
425
-
426
- @document.count.should == 1
427
- end
428
- end
429
-
430
- context "Destroying all documents" do
431
- setup do
432
- @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
433
- @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
434
- @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
435
- end
436
-
437
- should "remove all documents when given no conditions" do
438
- @document.destroy_all
439
- @document.count.should == 0
440
- end
441
-
442
- should "only remove matching documents when given conditions" do
443
- @document.destroy_all(:fname => 'John')
444
- @document.count.should == 2
445
- @document.destroy_all(:age => 26)
446
- @document.count.should == 1
447
- end
448
-
449
- should "convert the conditions to mongo criteria" do
450
- @document.destroy_all(:age => [26, 27])
451
- @document.count.should == 1
452
- end
453
- end
454
-
455
- context "Counting documents in collection" do
456
- setup do
457
- @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
458
- @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
459
- @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
460
- end
461
-
462
- should "count all with no arguments" do
463
- @document.count.should == 3
464
- end
465
-
466
- should "return 0 if there are no documents in the collection" do
467
- @document.delete_all
468
- @document.count.should == 0
469
- end
470
-
471
- should "return 0 if the collection does not exist" do
472
- klass = Class.new do
473
- include MongoMapper::Document
474
- collection 'foobarbazwickdoesnotexist'
475
- end
476
-
477
- klass.count.should == 0
478
- end
479
-
480
- should "return count for matching documents if conditions provided" do
481
- @document.count(:age => 27).should == 1
482
- end
483
-
484
- should "convert the conditions to mongo criteria" do
485
- @document.count(:age => [26, 27]).should == 2
486
- end
487
- end
488
-
489
- context "Indexing" do
490
- setup do
491
- @document.collection.drop_indexes
492
- end
493
-
494
- should "allow creating index for a key" do
495
- lambda {
496
- @document.ensure_index :fname
497
- }.should change { @document.collection.index_information.size }.by(1)
498
-
499
- index = @document.collection.index_information['fname_1']
500
- index.should_not be_nil
501
- index.should include(['fname', 1])
502
- end
503
-
504
- should "allow creating unique index for a key" do
505
- @document.collection.expects(:create_index).with(:fname, true)
506
- @document.ensure_index :fname, :unique => true
507
- end
508
-
509
- should "allow creating index on multiple keys" do
510
- lambda {
511
- @document.ensure_index [[:fname, 1], [:lname, -1]]
512
- }.should change { @document.collection.index_information.size }.by(1)
513
-
514
- index = @document.collection.index_information['lname_-1_fname_1']
515
- index.should_not be_nil
516
- index.should include(['fname', 1])
517
- index.should include(['lname', -1])
518
- end
519
-
520
- should "work with :index shortcut when defining key" do
521
- lambda {
522
- @document.key :father, String, :index => true
523
- }.should change { @document.collection.index_information.size }.by(1)
524
-
525
- index = @document.collection.index_information['father_1']
526
- index.should_not be_nil
527
- index.should include(['father', 1])
528
- end
529
- end
530
- end # Database operations
531
-
532
- context "An instance of a document" do
533
- setup do
534
- @document = Class.new do
535
- include MongoMapper::Document
536
-
537
- key :name, String
538
- key :age, Integer
539
- end
540
- @document.collection.clear
541
- end
542
-
543
- should "have access to the class's collection" do
544
- doc = @document.new
545
- doc.collection.should == @document.collection
546
- end
547
-
548
- should "automatically have an _id key" do
549
- @document.keys.keys.should include('_id')
550
- end
551
-
552
- should "automatically have a created_at key" do
553
- @document.keys.keys.should include('created_at')
554
- end
555
-
556
- should "automatically have an updated_at key" do
557
- @document.keys.keys.should include('updated_at')
558
- end
559
-
560
- should "use default values if defined for keys" do
561
- @document.key :active, Boolean, :default => true
562
-
563
- @document.new.active.should be_true
564
- @document.new(:active => false).active.should be_false
565
- end
566
-
567
- context "new?" do
568
- should "be true if no id" do
569
- @document.new.new?.should be(true)
570
- end
571
-
572
- should "be true if has id but id not in database" do
573
- @document.new('_id' => 1).new?.should be(true)
574
- end
575
-
576
- should "be false if has id and id is in database" do
577
- doc = @document.create(:name => 'John Nunemaker', :age => 27)
578
- doc.new?.should be(false)
579
- end
580
- end
581
-
582
- context "mass assigning keys" do
583
- should "update values for keys provided" do
584
- doc = @document.new(:name => 'foobar', :age => 10)
585
- doc.attributes = {:name => 'new value', :age => 5}
586
- doc.attributes[:name].should == 'new value'
587
- doc.attributes[:age].should == 5
588
- end
589
-
590
- should "not update values for keys that were not provided" do
591
- doc = @document.new(:name => 'foobar', :age => 10)
592
- doc.attributes = {:name => 'new value'}
593
- doc.attributes[:name].should == 'new value'
594
- doc.attributes[:age].should == 10
595
- end
596
-
597
- should "ignore keys that do not exist" do
598
- doc = @document.new(:name => 'foobar', :age => 10)
599
- doc.attributes = {:name => 'new value', :foobar => 'baz'}
600
- doc.attributes[:name].should == 'new value'
601
- doc.attributes[:foobar].should be(nil)
602
- end
603
-
604
- should "typecast key values" do
605
- doc = @document.new(:name => 1234, :age => '21')
606
- doc.name.should == '1234'
607
- doc.age.should == 21
608
- end
609
- end
610
-
611
- context "requesting keys" do
612
- should "default to empty hash" do
613
- doc = @document.new
614
- doc.attributes.should == {}
615
- end
616
-
617
- should "return all keys that aren't nil" do
618
- doc = @document.new(:name => 'string', :age => nil)
619
- doc.attributes.should == {'name' => 'string'}
620
- end
621
- end
622
-
623
- context "key shorcuts" do
624
- should "be able to read key with []" do
625
- doc = @document.new(:name => 'string')
626
- doc[:name].should == 'string'
627
- end
628
-
629
- should "be able to write key value with []=" do
630
- doc = @document.new
631
- doc[:name] = 'string'
632
- doc[:name].should == 'string'
633
- end
634
- end
635
-
636
- context "indifferent access" do
637
- should "be enabled for keys" do
638
- doc = @document.new(:name => 'string')
639
- doc.attributes[:name].should == 'string'
640
- doc.attributes['name'].should == 'string'
641
- end
642
- end
643
-
644
- context "reading an attribute" do
645
- should "work for defined keys" do
646
- doc = @document.new(:name => 'string')
647
- doc.name.should == 'string'
648
- end
649
-
650
- should "raise no method error for undefined keys" do
651
- doc = @document.new
652
- lambda { doc.fart }.should raise_error(NoMethodError)
653
- end
654
-
655
- should "know if reader defined" do
656
- doc = @document.new
657
- doc.reader?('name').should be(true)
658
- doc.reader?(:name).should be(true)
659
- doc.reader?('age').should be(true)
660
- doc.reader?(:age).should be(true)
661
- doc.reader?('foobar').should be(false)
662
- doc.reader?(:foobar).should be(false)
663
- end
664
-
665
- should "be accessible for use in the model" do
666
- @document.class_eval do
667
- def name_and_age
668
- "#{read_attribute(:name)} (#{read_attribute(:age)})"
669
- end
670
- end
671
-
672
- doc = @document.new(:name => 'John', :age => 27)
673
- doc.name_and_age.should == 'John (27)'
674
- end
675
- end
676
-
677
- context "reading an attribute before typcasting" do
678
- should "work for defined keys" do
679
- doc = @document.new(:name => 12)
680
- doc.name_before_typecast.should == 12
681
- end
682
-
683
- should "raise no method error for undefined keys" do
684
- doc = @document.new
685
- lambda { doc.foo_before_typecast }.should raise_error(NoMethodError)
686
- end
687
-
688
- should "be accessible for use in a document" do
689
- @document.class_eval do
690
- def untypcasted_name
691
- read_attribute_before_typecast(:name)
692
- end
693
- end
694
-
695
- doc = @document.new(:name => 12)
696
- doc.name.should == '12'
697
- doc.untypcasted_name.should == 12
698
- end
699
- end
700
-
701
- context "writing an attribute" do
702
- should "work for defined keys" do
703
- doc = @document.new
704
- doc.name = 'John'
705
- doc.name.should == 'John'
706
- end
707
-
708
- should "raise no method error for undefined keys" do
709
- doc = @document.new
710
- lambda { doc.fart = 'poof!' }.should raise_error(NoMethodError)
711
- end
712
-
713
- should "typecast value" do
714
- doc = @document.new
715
- doc.name = 1234
716
- doc.name.should == '1234'
717
- doc.age = '21'
718
- doc.age.should == 21
719
- end
720
-
721
- should "know if writer defined" do
722
- doc = @document.new
723
- doc.writer?('name').should be(true)
724
- doc.writer?('name=').should be(true)
725
- doc.writer?(:name).should be(true)
726
- doc.writer?('age').should be(true)
727
- doc.writer?('age=').should be(true)
728
- doc.writer?(:age).should be(true)
729
- doc.writer?('foobar').should be(false)
730
- doc.writer?('foobar=').should be(false)
731
- doc.writer?(:foobar).should be(false)
732
- end
733
-
734
- should "be accessible for use in the model" do
735
- @document.class_eval do
736
- def name_and_age=(new_value)
737
- new_value.match(/([^\(\s]+) \((.*)\)/)
738
- write_attribute :name, $1
739
- write_attribute :age, $2
740
- end
741
- end
742
-
743
- doc = @document.new
744
- doc.name_and_age = 'Frank (62)'
745
- doc.name.should == 'Frank'
746
- doc.age.should == 62
747
- end
748
- end # writing an attribute
749
-
750
- context "respond_to?" do
751
- setup do
752
- @doc = @document.new
753
- end
754
-
755
- should "work for readers" do
756
- @doc.respond_to?(:name).should be_true
757
- @doc.respond_to?('name').should be_true
758
- end
759
-
760
- should "work for writers" do
761
- @doc.respond_to?(:name=).should be_true
762
- @doc.respond_to?('name=').should be_true
763
- end
764
-
765
- should "work for readers before typecast" do
766
- @doc.respond_to?(:name_before_typecast).should be_true
767
- @doc.respond_to?('name_before_typecast').should be_true
768
- end
769
- end
770
-
771
- context "equality" do
772
- should "be equal if id and class are the same" do
773
- (@document.new('_id' => 1) == @document.new('_id' => 1)).should be(true)
774
- end
775
-
776
- should "not be equal if class same but id different" do
777
- (@document.new('_id' => 1) == @document.new('_id' => 2)).should be(false)
778
- end
779
-
780
- should "not be equal if id same but class different" do
781
- @another_document = Class.new do
782
- include MongoMapper::Document
783
- end
784
-
785
- (@document.new('_id' => 1) == @another_document.new('_id' => 1)).should be(false)
786
- end
787
- end
788
-
789
- context "Saving a new document" do
790
- setup do
791
- @doc = @document.new(:name => 'John Nunemaker', :age => '27')
792
- @doc.save
793
- end
794
-
795
- should "insert document into the collection" do
796
- @document.count.should == 1
797
- end
798
-
799
- should "assign an id for the document" do
800
- @doc.id.should_not be(nil)
801
- @doc.id.size.should == 24
802
- end
803
-
804
- should "save attributes" do
805
- @doc.name.should == 'John Nunemaker'
806
- @doc.age.should == 27
807
- end
808
-
809
- should "update attributes in the database" do
810
- from_db = @document.find(@doc.id)
811
- from_db.should == @doc
812
- from_db.name.should == 'John Nunemaker'
813
- from_db.age.should == 27
814
- end
815
- end
816
-
817
- context "Saving an existing document" do
818
- setup do
819
- @doc = @document.create(:name => 'John Nunemaker', :age => '27')
820
- @doc.name = 'John Doe'
821
- @doc.age = 30
822
- @doc.save
823
- end
824
-
825
- should "not insert document into collection" do
826
- @document.count.should == 1
827
- end
828
-
829
- should "update attributes" do
830
- @doc.name.should == 'John Doe'
831
- @doc.age.should == 30
832
- end
833
-
834
- should "update attributes in the database" do
835
- from_db = @document.find(@doc.id)
836
- from_db.name.should == 'John Doe'
837
- from_db.age.should == 30
838
- end
839
- end
840
-
841
- context "Calling update attributes on a new document" do
842
- setup do
843
- @doc = @document.new(:name => 'John Nunemaker', :age => '27')
844
- @doc.update_attributes(:name => 'John Doe', :age => 30)
845
- end
846
-
847
- should "insert document into the collection" do
848
- @document.count.should == 1
849
- end
850
-
851
- should "assign an id for the document" do
852
- @doc.id.should_not be(nil)
853
- @doc.id.size.should == 24
854
- end
855
-
856
- should "save attributes" do
857
- @doc.name.should == 'John Doe'
858
- @doc.age.should == 30
859
- end
860
-
861
- should "update attributes in the database" do
862
- from_db = @document.find(@doc.id)
863
- from_db.should == @doc
864
- from_db.name.should == 'John Doe'
865
- from_db.age.should == 30
866
- end
867
- end
868
-
869
- context "Updating an existing document using update attributes" do
870
- setup do
871
- @doc = @document.create(:name => 'John Nunemaker', :age => '27')
872
- @doc.update_attributes(:name => 'John Doe', :age => 30)
873
- end
874
-
875
- should "not insert document into collection" do
876
- @document.count.should == 1
877
- end
878
-
879
- should "update attributes" do
880
- @doc.name.should == 'John Doe'
881
- @doc.age.should == 30
882
- end
883
-
884
- should "update attributes in the database" do
885
- from_db = @document.find(@doc.id)
886
- from_db.name.should == 'John Doe'
887
- from_db.age.should == 30
888
- end
889
- end
890
-
891
- context "Destroying a document that exists" do
892
- setup do
893
- @doc = @document.create(:name => 'John Nunemaker', :age => '27')
894
- @doc.destroy
895
- end
896
-
897
- should "remove the document from the collection" do
898
- @document.count.should == 0
899
- end
900
-
901
- should "raise error if assignment is attempted" do
902
- lambda { @doc.name = 'Foo' }.should raise_error(TypeError)
903
- end
904
- end
905
-
906
- context "Destroying a document that is a new" do
907
- setup do
908
- setup do
909
- @doc = @document.new(:name => 'John Nunemaker', :age => '27')
910
- @doc.destroy
911
- end
912
-
913
- should "not affect collection count" do
914
- @document.collection.count.should == 0
915
- end
916
-
917
- should "raise error if assignment is attempted" do
918
- lambda { @doc.name = 'Foo' }.should raise_error(TypeError)
919
- end
920
- end
921
- end
922
-
923
- context "timestamping" do
924
- should "set created_at and updated_at on create" do
925
- doc = @document.new(:name => 'John Nunemaker', :age => 27)
926
- doc.created_at.should be(nil)
927
- doc.updated_at.should be(nil)
928
- doc.save
929
- doc.created_at.should_not be(nil)
930
- doc.updated_at.should_not be(nil)
931
- end
932
-
933
- should "set updated_at on update but leave created_at alone" do
934
- doc = @document.create(:name => 'John Nunemaker', :age => 27)
935
- old_created_at = doc.created_at
936
- old_updated_at = doc.updated_at
937
- doc.name = 'John Doe'
938
- doc.save
939
- doc.created_at.should == old_created_at
940
- doc.updated_at.should_not == old_updated_at
941
- end
942
- end
943
- end # instance of a document
944
- end # DocumentTest