mongo_db 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
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