mongo_db 0.1.9 → 0.1.10

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 (51) hide show
  1. data/lib/mongo_db/driver/{core/collection.rb → collection.rb} +13 -5
  2. data/lib/mongo_db/driver/{core/database.rb → database.rb} +0 -0
  3. data/lib/mongo_db/driver/dynamic_finders.rb +41 -0
  4. data/lib/mongo_db/driver.rb +33 -2
  5. data/lib/mongo_db/migration/definition.rb +19 -0
  6. data/lib/mongo_db/migration/migration.rb +68 -0
  7. data/lib/mongo_db/migration/tasks.rb +19 -0
  8. data/lib/mongo_db/migration.rb +8 -0
  9. data/lib/mongo_db/model/assignment.rb +54 -0
  10. data/lib/mongo_db/model/callbacks.rb +36 -0
  11. data/lib/mongo_db/model/crud.rb +28 -0
  12. data/lib/mongo_db/model/db.rb +53 -0
  13. data/lib/mongo_db/model/misc.rb +14 -0
  14. data/lib/mongo_db/model/model.rb +10 -0
  15. data/lib/mongo_db/model/query.rb +36 -0
  16. data/lib/mongo_db/model/scope.rb +99 -0
  17. data/lib/mongo_db/model/spec.rb +12 -0
  18. data/lib/mongo_db/model/support/types.rb +110 -0
  19. data/lib/mongo_db/model/validation.rb +5 -0
  20. data/lib/mongo_db/model.rb +30 -0
  21. data/lib/mongo_db/object/object_serializer.rb +20 -21
  22. data/readme.md +132 -19
  23. data/spec/driver/{core/collection_spec.rb → collection_spec.rb} +13 -0
  24. data/spec/driver/{core/crud_spec.rb → crud_spec.rb} +0 -0
  25. data/spec/driver/{core/database_spec.rb → database_spec.rb} +0 -0
  26. data/spec/driver/dynamic_finders_spec.rb +50 -0
  27. data/spec/driver/{core/hash_helper_spec.rb → hash_helper_spec.rb} +0 -0
  28. data/spec/{model/example.rb → integration/am_conversion_spec.rb} +0 -0
  29. data/spec/integration/am_validation_spec.rb +40 -0
  30. data/spec/migration/migration_spec.rb +60 -0
  31. data/spec/model/assignment_spec.rb +79 -0
  32. data/spec/model/callbacks_spec.rb +47 -0
  33. data/spec/model/{model_crud.rb → crud_spec.rb} +46 -36
  34. data/spec/model/db_spec.rb +63 -0
  35. data/spec/model/misc_spec.rb +32 -0
  36. data/spec/model/query_spec.rb +47 -0
  37. data/spec/model/scope_spec.rb +149 -0
  38. data/spec/model/spec_helper.rb +4 -0
  39. data/spec/model/validation_spec.rb +37 -0
  40. data/spec/object/callbacks_spec.rb +6 -4
  41. data/spec/object/crud_shared.rb +1 -1
  42. data/spec/object/crud_spec.rb +15 -10
  43. data/spec/object/spec_helper.rb +3 -2
  44. data/spec/object/validation_spec.rb +4 -2
  45. metadata +39 -18
  46. data/lib/mongo_db/driver/core.rb +0 -29
  47. data/lib/mongo_db/driver/more/collection_finders.rb +0 -43
  48. data/lib/mongo_db/driver/more.rb +0 -10
  49. data/spec/driver/more/querying_spec.rb +0 -59
  50. data/spec/model/callbacks.rb +0 -100
  51. data/spec/test.rb +0 -10
@@ -0,0 +1,110 @@
1
+ #
2
+ # Boolean
3
+ #
4
+ module Mongo::Model::BooleanType
5
+ Mapping = {
6
+ true => true,
7
+ 'true' => true,
8
+ 'TRUE' => true,
9
+ 'True' => true,
10
+ 't' => true,
11
+ 'T' => true,
12
+ '1' => true,
13
+ 1 => true,
14
+ 1.0 => true,
15
+ false => false,
16
+ 'false' => false,
17
+ 'FALSE' => false,
18
+ 'False' => false,
19
+ 'f' => false,
20
+ 'F' => false,
21
+ '0' => false,
22
+ 0 => false,
23
+ 0.0 => false,
24
+ nil => nil
25
+ }
26
+
27
+ def cast value
28
+ if value.is_a? Boolean
29
+ value
30
+ else
31
+ Mapping[value] || false
32
+ end
33
+ end
34
+ end
35
+
36
+ class Boolean; end unless defined?(Boolean)
37
+
38
+ Boolean.extend Mongo::Model::BooleanType
39
+
40
+
41
+ #
42
+ # Date
43
+ #
44
+ require 'date'
45
+ Date.class_eval do
46
+ def self.cast value
47
+ if value.nil? || value == ''
48
+ nil
49
+ else
50
+ date = value.is_a?(::Date) || value.is_a?(::Time) ? value : ::Date.parse(value.to_s)
51
+ date.to_date
52
+ end
53
+ rescue
54
+ nil
55
+ end
56
+ end
57
+
58
+
59
+ #
60
+ # Float
61
+ #
62
+ Float.class_eval do
63
+ def self.cast value
64
+ value.nil? ? nil : value.to_f
65
+ end
66
+ end
67
+
68
+
69
+ #
70
+ # Integer
71
+ #
72
+ Integer.class_eval do
73
+ def self.cast value
74
+ value_to_i = value.to_i
75
+ if value_to_i == 0 && value != value_to_i
76
+ value.to_s =~ /^(0x|0b)?0+/ ? 0 : nil
77
+ else
78
+ value_to_i
79
+ end
80
+ end
81
+ end
82
+
83
+
84
+ #
85
+ # String
86
+ #
87
+ String.class_eval do
88
+ def self.cast value
89
+ value.nil? ? nil : value.to_s
90
+ end
91
+ end
92
+
93
+
94
+ #
95
+ # Time
96
+ #
97
+ Time.class_eval do
98
+ def self.cast value
99
+ if value.nil? || value == ''
100
+ nil
101
+ else
102
+ # time_class = ::Time.try(:zone).present? ? ::Time.zone : ::Time
103
+ # time = value.is_a?(::Time) ? value : time_class.parse(value.to_s)
104
+ # strip milliseconds as Ruby does micro and bson does milli and rounding rounded wrong
105
+ # at(time.to_i).utc if time
106
+
107
+ value.is_a?(::Time) ? value : Date.parse(value.to_s).to_time
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,5 @@
1
+ module Mongo::Model::Validation
2
+ def _valid?
3
+ !(respond_to?(:errors) and errors and !errors.empty?)
4
+ end
5
+ end
@@ -0,0 +1,30 @@
1
+ begin
2
+ require 'ruby_ext'
3
+ rescue LoadError => e
4
+ warn 'Model requires the ruby_ext gem, please install it'
5
+ raise e
6
+ end
7
+
8
+ require 'mongo_db/object'
9
+
10
+ module Mongo::Model; end
11
+
12
+ %w(
13
+ support/types
14
+
15
+ db
16
+ assignment
17
+ callbacks
18
+ validation
19
+ crud
20
+ query
21
+ scope
22
+ misc
23
+ model
24
+ ).each{|f| require "mongo_db/model/#{f}"}
25
+
26
+ module Mongo
27
+ module Model
28
+ inherit Db, Assignment, Callbacks, Validation, Crud, Query, Scope, Misc
29
+ end
30
+ end
@@ -27,7 +27,7 @@ class Mongo::ObjectSerializer
27
27
  opts, validate, callbacks = parse_object_options opts
28
28
 
29
29
  # before callbacks
30
- return false if callbacks and !run_callbacks(objects, :before_validate, :before_save, :before_create)
30
+ return false if callbacks and !run_callbacks(objects, [:before, :validate], [:before, :save], [:before, :create])
31
31
 
32
32
  # validation
33
33
  return false if validate and !valid?
@@ -40,7 +40,7 @@ class Mongo::ObjectSerializer
40
40
  update_internal_state!
41
41
 
42
42
  # after callbacks
43
- run_callbacks(objects, :after_create, :after_save, :after_validate) if callbacks
43
+ run_callbacks(objects, [:after, :create], [:after, :save], [:after, :validate]) if callbacks
44
44
 
45
45
  true
46
46
  end
@@ -52,18 +52,18 @@ class Mongo::ObjectSerializer
52
52
  # we need to sort out embedded objects into created, updated and destroyed
53
53
  created_objects, updated_objects, destroyed_objects = [], [], []
54
54
  if callbacks
55
- original_ids = original_embedded_objects.collect{|obj| obj.object_id}.to_set
55
+ original_ids = original_objects.collect{|obj| obj.object_id}.to_set
56
56
  objects.each do |obj|
57
57
  (original_ids.include?(obj.object_id) ? updated_objects : created_objects) << obj
58
58
  end
59
59
 
60
60
  objects_ids = objects.collect{|obj| obj.object_id}.to_set
61
- destroyed_objects = original_embedded_objects.select{|obj| !objects_ids.include?(obj.object_id)}
61
+ destroyed_objects = original_objects.select{|obj| !objects_ids.include?(obj.object_id)}
62
62
 
63
63
  all_successfull = [
64
- run_callbacks(created_objects, :before_validate, :before_save, :before_create),
65
- run_callbacks(updated_objects, :before_validate, :before_save, :before_update),
66
- run_callbacks(destroyed_objects, :before_validate, :before_destroy)
64
+ run_callbacks(created_objects, [:before, :validate], [:before, :save], [:before, :create]),
65
+ run_callbacks(updated_objects, [:before, :validate], [:before, :save], [:before, :update]),
66
+ run_callbacks(destroyed_objects, [:before, :validate], [:before, :destroy])
67
67
  ].reduce(:&)
68
68
 
69
69
  return false unless all_successfull
@@ -80,9 +80,9 @@ class Mongo::ObjectSerializer
80
80
 
81
81
  # after callbacks
82
82
  if callbacks
83
- run_callbacks(created_objects, :after_create, :after_save, :after_validate)
84
- run_callbacks(updated_objects, :after_update, :after_save, :after_validate)
85
- run_callbacks(destroyed_objects, :after_destroy, :after_validate)
83
+ run_callbacks(created_objects, [:after, :create], [:after, :save], [:after, :validate])
84
+ run_callbacks(updated_objects, [:after, :update], [:after, :save], [:after, :validate])
85
+ run_callbacks(destroyed_objects, [:after, :destroy], [:after, :validate])
86
86
  end
87
87
 
88
88
  true
@@ -94,8 +94,8 @@ class Mongo::ObjectSerializer
94
94
  # before callbacks
95
95
  if callbacks
96
96
  # we need to run :destroy callbacks also on detached embedded objects.
97
- all_objects = (objects + original_embedded_objects).uniq{|o| o.object_id}
98
- return false unless run_callbacks(all_objects, :before_validate, :before_destroy)
97
+ all_objects = (objects + original_objects).uniq{|o| o.object_id}
98
+ return false unless run_callbacks(all_objects, [:before, :validate], [:before, :destroy])
99
99
  end
100
100
 
101
101
  # validation
@@ -107,7 +107,7 @@ class Mongo::ObjectSerializer
107
107
  update_internal_state!
108
108
 
109
109
  # after callbacks
110
- run_callbacks(objects, :after_destroy, :after_validate) if callbacks
110
+ run_callbacks(objects, [:after, :destroy], [:after, :validate]) if callbacks
111
111
 
112
112
  true
113
113
  end
@@ -127,16 +127,15 @@ class Mongo::ObjectSerializer
127
127
  true
128
128
  end
129
129
 
130
- def run_callbacks objects, *names
131
- all_successfull = true
132
- names.each do |name|
130
+ def run_callbacks objects, *callbacks
131
+ callbacks.each do |type, method_name|
133
132
  objects.each do |obj|
134
133
  if obj.respond_to? :_run_callbacks
135
- all_successfull = false if obj._run_callbacks(name) == false
134
+ return false if obj._run_callbacks(type, method_name) == false
136
135
  end
137
136
  end
138
137
  end
139
- all_successfull
138
+ true
140
139
  end
141
140
 
142
141
  def objects
@@ -148,12 +147,12 @@ class Mongo::ObjectSerializer
148
147
  end
149
148
 
150
149
  def update_internal_state!
151
- self.original_embedded_objects = objects if Mongo.defaults[:callbacks]
150
+ self.original_objects = objects if Mongo.defaults[:callbacks]
152
151
  end
153
152
 
154
153
  protected
155
- def original_embedded_objects; object.instance_variable_get(:@_original_embedded_objects) end
156
- def original_embedded_objects= objects; object.instance_variable_set(:@_original_embedded_objects, objects) end
154
+ def original_objects; object.instance_variable_get(:@_original_objects) end
155
+ def original_objects= objects; object.instance_variable_set(:@_original_objects, objects) end
157
156
 
158
157
  def parse_object_options opts
159
158
  opts = opts.clone
data/readme.md CHANGED
@@ -1,10 +1,10 @@
1
1
  Object Model & Ruby driver enhancements for MongoDB.
2
2
 
3
- 1. Driver enchancements
4
- 2. Persistence for any Ruby object
5
- 3. Object Model (callbacks, validations, mass-assignment, finders, ...) (work in progress)
3
+ 1. Driver enchancements & Migrations.
4
+ 2. Persistence for any Ruby object.
5
+ 3. Object Model (callbacks, validations, mass-assignment, finders, ...) (work in progress).
6
6
 
7
- Lower layers are completely independent from upper, use only what You need. There are also support for migrations.
7
+ Lower layers are independent from upper, use only what You need.
8
8
 
9
9
  # MongoDB driver enhancements
10
10
 
@@ -16,7 +16,7 @@ These enhancements alter the driver's API and made it more simple and intuitive.
16
16
  - 100% backward compatibility with original driver API (if not - it's a bug, report it please)
17
17
 
18
18
  ``` ruby
19
- require 'mongo_db/driver/core'
19
+ require 'mongo_db/driver'
20
20
 
21
21
  # Changing some defaults.
22
22
  Mongo.defaults.merge! symbolize: true, multi: true, safe: true
@@ -46,15 +46,8 @@ db.units.all name: 'Zeratul' # => [zeratul]
46
46
  db.units.all name: 'Zeratul' do |unit|
47
47
  unit # => zeratul
48
48
  end
49
- ```
50
-
51
- Optionall stuff - simple query enchancements:
52
-
53
- ``` ruby
54
- # Finders.
55
- require 'mongo_db/driver/more'
56
49
 
57
- # Simple finders (bang versions also availiable).
50
+ # Dynamic Finders (bang versions also availiable).
58
51
  db.units.by_name 'Zeratul' # => zeratul
59
52
  db.units.first_by_name 'Zeratul' # => zeratul
60
53
  db.units.all_by_name 'Zeratul' # => [zeratul]
@@ -64,6 +57,8 @@ Mongo.defaults.merge! convert_underscore_to_dollar: true
64
57
  db.units.all name: {_gt: 'Z'} # => [zeratul]
65
58
  ```
66
59
 
60
+ Source: examples/driver.rb
61
+
67
62
  More docs - there's no need for more docs, the whole point of this extension is to be small, intuitive, 100% compatible with the official driver, and require no extra knowledge.
68
63
  So, please use standard Ruby driver documentation.
69
64
 
@@ -127,18 +122,135 @@ Mongo.defaults.merge! convert_underscore_to_dollar: true
127
122
  db.units.all name: {_gt: 'Z'} # => [zeratul]
128
123
  ```
129
124
 
130
- # Migrations (work in progress)
125
+ Source: examples/object.rb
131
126
 
132
127
  # Object Model (work in progress)
133
128
 
134
129
  Model designed after the excellent "Domain-Driven Design" book by Eric Evans.
135
130
 
136
- - Very small.
137
- - Minimum extra abstraction, trying to keep things as close to the MongoDB semantic as possible.
131
+ - Very small, see [code stats][:code_stats].
132
+ - The same API for pure driver and Models.
133
+ - Minimum extra abstractions, trying to keep things as close to the MongoDB semantic as possible.
138
134
  - Schema-less, dynamic (with ability to specify types for mass-assignment).
139
135
  - Models can be saved to any collection.
140
- - Full support for embedded objects (and MDD composite pattern).
141
- - Doesn't try to mimic ActiveRecord, it's differrent and designed to get most of MongoDB.
136
+ - Full support for embedded objects (validations, callbacks, ...).
137
+ - Scope, default_scope
138
+ - Doesn't try to mimic ActiveRecord, MongoDB is differrent and this tool designed to get most of it.
139
+
140
+ Existing ODM like MongoMapper and Mongoid are trying to hide simple but non-standard API of MongoDB by covering it with complicated but familiar API.
141
+ This ODM exposes simplicity of MongoDB and leverages it's differences.
142
+
143
+ ``` ruby
144
+ # Connecting to MongoDB.
145
+ require 'mongo_db/model'
146
+ Mongo.defaults.merge! symbolize: true, multi: true, safe: true
147
+ connection = Mongo::Connection.new
148
+ db = connection.db 'default_test'
149
+ db.units.drop
150
+ Mongo::Model.db = db
151
+
152
+ # Let's define the game unit.
153
+ class Unit
154
+ inherit Mongo::Model
155
+ collection :units
156
+
157
+ attr_accessor :name, :status, :stats
158
+
159
+ scope :alive, status: 'alive'
160
+
161
+ class Stats
162
+ inherit Mongo::Model
163
+ attr_accessor :attack, :life, :shield
164
+ end
165
+ end
166
+
167
+ # Create.
168
+ zeratul = Unit.new.set(name: 'Zeratul', status: 'alive', stats: Unit::Stats.new.set(attack: 85, life: 300, shield: 100))
169
+ tassadar = Unit.new.set(name: 'Tassadar', status: 'dead', stats: Unit::Stats.new.set(attack: 0, life: 80, shield: 300))
170
+
171
+ zeratul.save
172
+ tassadar.save
173
+
174
+ # Udate (we made error - mistakenly set Tassadar's attack as zero, let's fix it).
175
+ tassadar.stats.attack = 20
176
+ tassadar.save
177
+
178
+ # Querying first & all, there's also :each, the same as :all.
179
+ Unit.first name: 'Zeratul' # => zeratul
180
+ Unit.all name: 'Zeratul' # => [zeratul]
181
+ Unit.all name: 'Zeratul' do |unit|
182
+ unit # => zeratul
183
+ end
184
+
185
+ # Simple finders (bang versions also availiable).
186
+ Unit.by_name 'Zeratul' # => zeratul
187
+ Unit.first_by_name 'Zeratul' # => zeratul
188
+ Unit.all_by_name 'Zeratul' # => [zeratul]
189
+
190
+ # Scopes.
191
+ Unit.alive.count # => 1
192
+ Unit.alive.first # => zeratul
193
+
194
+ # Callbacks & callbacks on embedded models.
195
+
196
+ # Validations.
197
+
198
+ # Save model to any collection.
199
+ ```
200
+
201
+ Source: examples/model.rb
202
+
203
+ # Migrations
204
+
205
+ Define migration steps, specify desired version and apply it (usually all this should be done via Rake task).
206
+
207
+ ``` ruby
208
+ require 'mongo_db/migration'
209
+
210
+ # Connection & db.
211
+ connection = Mongo::Connection.new
212
+ db = connection.db 'default_test'
213
+ db.units.drop
214
+
215
+ # Initialize migration (usually all this should be done inside of :migrate
216
+ # rake task).
217
+ migration = Mongo::Migration.new db
218
+
219
+ # Define migrations.
220
+ # Usually they are defined as files in some folder and You loading it by
221
+ # using something like this:
222
+ # Dir['<runtime_dir>/db/migrations/*.rb'].each{|fname| load fname}
223
+ migration.add 1 do |m|
224
+ m.up{|db| db.units.save name: 'Zeratul'}
225
+ m.down{|db| db.units.remove name: 'Zeratul'}
226
+ end
227
+
228
+ # Let's add another one.
229
+ migration.add 2 do |m|
230
+ m.up{|db| db.units.save name: 'Tassadar'}
231
+ m.down{|db| db.units.remove name: 'Tassadar'}
232
+ end
233
+
234
+ # Specify what version of database You need and apply migration.
235
+ migration.update 2
236
+
237
+ migration.current_version # => 2
238
+ db.units.count # => 2
239
+
240
+ # You can rollback it the same way.
241
+ migration.update 0
242
+
243
+ migration.current_version # => 0
244
+ db.units.count # => 0
245
+
246
+ # To update to the highest version just call it without the version specified
247
+ migration.update
248
+
249
+ migration.current_version # => 2
250
+ db.units.count # => 2
251
+ ```
252
+
253
+ Source: examples/migration.rb
142
254
 
143
255
  # Installation
144
256
 
@@ -151,4 +263,5 @@ gem install mongo_db
151
263
  Copyright (c) Alexey Petrushin, http://petrush.in, released under the MIT license.
152
264
 
153
265
  [mongo_mapper_ext]: https://github.com/alexeypetrushin/mongo_mapper_ext
154
- [mongoid_misc]: https://github.com/alexeypetrushin/mongoid_misc
266
+ [mongoid_misc]: https://github.com/alexeypetrushin/mongoid_misc
267
+ [code_stats]: https://raw.github.com/alexeypetrushin/mongo_db/master/doc/code_stats.png
@@ -67,4 +67,17 @@ describe "Collection" do
67
67
  list.size.should == 1
68
68
  list.first[:name].should == 'Zeratul'
69
69
  end
70
+
71
+ it 'count' do
72
+ db.units.count(name: 'Zeratul').should == 0
73
+ db.units.save name: 'Zeratul'
74
+ db.units.save name: 'Tassadar'
75
+ db.units.count(name: 'Zeratul').should == 1
76
+ end
77
+
78
+ it "underscore to dollar" do
79
+ db.units.save name: 'Jim', age: 34
80
+ db.units.save name: 'Zeratul', age: 600
81
+ db.units.all(age: {_lt: 100}).count.should == 1
82
+ end
70
83
  end
File without changes
@@ -0,0 +1,50 @@
1
+ require 'driver/spec_helper'
2
+
3
+ describe "Dynamic Finders" do
4
+ with_mongo
5
+
6
+ before :all do
7
+ class FindersStub
8
+ include Mongo::DynamicFinders
9
+ end
10
+ end
11
+
12
+ after(:all){remove_constants :FindersStub}
13
+
14
+ it "parse_finder" do
15
+ [
16
+ [:first_by_name, 'Jim'], [:first, {name: 'Jim'}],
17
+ [:first_by_name!, 'Jim'], [:first!, {name: 'Jim'}],
18
+
19
+ [:all_by_name, 'Jim'], [:all, {name: 'Jim'}],
20
+
21
+ [:each_by_name, 'Jim'], [:each, {name: 'Jim'}],
22
+
23
+ [:by_name, 'Jim'], [:first, {name: 'Jim'}],
24
+ [:by_name!, 'Jim'], [:first!, {name: 'Jim'}],
25
+
26
+ [:first_by_id, 'id'], [:first, {_id: 'id'}],
27
+ [:first_by_id!, 'id'], [:first!, {_id: 'id'}],
28
+ [:by_id, 'id'], [:first, {_id: 'id'}],
29
+ [:by_id!, 'id'], [:first!, {_id: 'id'}],
30
+ ].each_slice 2 do |check, expectation|
31
+ stub = FindersStub.new
32
+ stub.should_receive(expectation.first).with(expectation.last)
33
+ stub.send check.first, check.last
34
+ end
35
+
36
+ stub = FindersStub.new
37
+ -> {stub.invalid_finder 'a', 'b'}.should raise_error(NoMethodError)
38
+ end
39
+
40
+ it "should allow to use bang version only with :first" do
41
+ stub = FindersStub.new
42
+ -> {stub.all_by_name!('Jim')}.should raise_error(/can't use bang/)
43
+ end
44
+
45
+ it 'integration with collection' do
46
+ db.units.first_by_name('Jim').should be_nil
47
+ db.units.save name: 'Jim'
48
+ db.units.first_by_name('Jim')[:name].should == 'Jim'
49
+ end
50
+ end
@@ -0,0 +1,40 @@
1
+ require 'model/spec_helper'
2
+
3
+ begin
4
+ require 'active_model'
5
+
6
+ describe "Validations" do
7
+ with_mongo_model
8
+
9
+ before do
10
+ class Unit
11
+ inherit Mongo::Model
12
+ collection :units
13
+
14
+ include ActiveModel::Validations
15
+
16
+ attr_accessor :name, :status
17
+
18
+ validates_presence_of :name
19
+ end
20
+ end
21
+
22
+ after{remove_constants :Unit}
23
+
24
+ it "ActiveModel integration smoke test" do
25
+ unit = Unit.new
26
+ unit.should be_invalid
27
+ unit.errors.size.should == 1
28
+ unit.errors.first.first.should == :name
29
+ unit.save.should be_false
30
+
31
+ unit.name = 'Zeratul'
32
+ unit.should be_valid
33
+ unit.errors.should be_empty
34
+ unit.save.should be_true
35
+ end
36
+ end
37
+
38
+ rescue LoadError => e
39
+ warn 'No ActiveModel, integration with ActiveModel::Validations spec will be skipped.'
40
+ end
@@ -0,0 +1,60 @@
1
+ require 'driver/spec_helper'
2
+ require 'mongo_db/migration'
3
+
4
+ describe "Migration" do
5
+ with_mongo
6
+ before{@migration = Mongo::Migration.new mongo.db}
7
+
8
+ it "shouldn't update if versions are the same" do
9
+ @migration.update(0).should be_false
10
+ end
11
+
12
+ it "migration should provide access to database" do
13
+ @migration.add 1 do |m|
14
+ m.up do |db|
15
+ db.users.save name: 'Bob'
16
+ end
17
+ end
18
+ @migration.update(1).should be_true
19
+ db.users.count.should == 1
20
+ end
21
+
22
+ it "increase_db_version" do
23
+ @migration.current_version.should == 0
24
+
25
+ check = mock
26
+ @migration.add 1 do |m|
27
+ m.up{check.up}
28
+ end
29
+
30
+ check.should_receive :up
31
+ @migration.update(1).should be_true
32
+ @migration.current_version.should == 1
33
+ end
34
+
35
+ it "decrease_db_version" do
36
+ check = mock
37
+ @migration.add 1 do |m|
38
+ m.up{check.up}
39
+ m.down{check.down}
40
+ end
41
+
42
+ check.should_receive :up
43
+ @migration.update(1).should be_true
44
+
45
+ check.should_receive :down
46
+ @migration.update(0).should be_true
47
+ @migration.current_version.should == 0
48
+ end
49
+
50
+ it "should automigrate to highest version" do
51
+ @migration.add 1 do |m|
52
+ m.up{}
53
+ end
54
+ @migration.add 2 do |m|
55
+ m.up{}
56
+ end
57
+ @migration.update.should be_true
58
+ @migration.current_version.should == 2
59
+ end
60
+ end