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.
- data/lib/mongo_db/driver/{core/collection.rb → collection.rb} +13 -5
- data/lib/mongo_db/driver/{core/database.rb → database.rb} +0 -0
- data/lib/mongo_db/driver/dynamic_finders.rb +41 -0
- data/lib/mongo_db/driver.rb +33 -2
- data/lib/mongo_db/migration/definition.rb +19 -0
- data/lib/mongo_db/migration/migration.rb +68 -0
- data/lib/mongo_db/migration/tasks.rb +19 -0
- data/lib/mongo_db/migration.rb +8 -0
- data/lib/mongo_db/model/assignment.rb +54 -0
- data/lib/mongo_db/model/callbacks.rb +36 -0
- data/lib/mongo_db/model/crud.rb +28 -0
- data/lib/mongo_db/model/db.rb +53 -0
- data/lib/mongo_db/model/misc.rb +14 -0
- data/lib/mongo_db/model/model.rb +10 -0
- data/lib/mongo_db/model/query.rb +36 -0
- data/lib/mongo_db/model/scope.rb +99 -0
- data/lib/mongo_db/model/spec.rb +12 -0
- data/lib/mongo_db/model/support/types.rb +110 -0
- data/lib/mongo_db/model/validation.rb +5 -0
- data/lib/mongo_db/model.rb +30 -0
- data/lib/mongo_db/object/object_serializer.rb +20 -21
- data/readme.md +132 -19
- data/spec/driver/{core/collection_spec.rb → collection_spec.rb} +13 -0
- data/spec/driver/{core/crud_spec.rb → crud_spec.rb} +0 -0
- data/spec/driver/{core/database_spec.rb → database_spec.rb} +0 -0
- data/spec/driver/dynamic_finders_spec.rb +50 -0
- data/spec/driver/{core/hash_helper_spec.rb → hash_helper_spec.rb} +0 -0
- data/spec/{model/example.rb → integration/am_conversion_spec.rb} +0 -0
- data/spec/integration/am_validation_spec.rb +40 -0
- data/spec/migration/migration_spec.rb +60 -0
- data/spec/model/assignment_spec.rb +79 -0
- data/spec/model/callbacks_spec.rb +47 -0
- data/spec/model/{model_crud.rb → crud_spec.rb} +46 -36
- data/spec/model/db_spec.rb +63 -0
- data/spec/model/misc_spec.rb +32 -0
- data/spec/model/query_spec.rb +47 -0
- data/spec/model/scope_spec.rb +149 -0
- data/spec/model/spec_helper.rb +4 -0
- data/spec/model/validation_spec.rb +37 -0
- data/spec/object/callbacks_spec.rb +6 -4
- data/spec/object/crud_shared.rb +1 -1
- data/spec/object/crud_spec.rb +15 -10
- data/spec/object/spec_helper.rb +3 -2
- data/spec/object/validation_spec.rb +4 -2
- metadata +39 -18
- data/lib/mongo_db/driver/core.rb +0 -29
- data/lib/mongo_db/driver/more/collection_finders.rb +0 -43
- data/lib/mongo_db/driver/more.rb +0 -10
- data/spec/driver/more/querying_spec.rb +0 -59
- data/spec/model/callbacks.rb +0 -100
- 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,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, :
|
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, :
|
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 =
|
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 =
|
61
|
+
destroyed_objects = original_objects.select{|obj| !objects_ids.include?(obj.object_id)}
|
62
62
|
|
63
63
|
all_successfull = [
|
64
|
-
run_callbacks(created_objects, :
|
65
|
-
run_callbacks(updated_objects, :
|
66
|
-
run_callbacks(destroyed_objects, :
|
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, :
|
84
|
-
run_callbacks(updated_objects, :
|
85
|
-
run_callbacks(destroyed_objects, :
|
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 +
|
98
|
-
return false unless run_callbacks(all_objects, :
|
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, :
|
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, *
|
131
|
-
|
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
|
-
|
134
|
+
return false if obj._run_callbacks(type, method_name) == false
|
136
135
|
end
|
137
136
|
end
|
138
137
|
end
|
139
|
-
|
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.
|
150
|
+
self.original_objects = objects if Mongo.defaults[:callbacks]
|
152
151
|
end
|
153
152
|
|
154
153
|
protected
|
155
|
-
def
|
156
|
-
def
|
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
|
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
|
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
|
-
#
|
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
|
-
|
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
|
-
-
|
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 (
|
141
|
-
-
|
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
|
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
|
File without changes
|
File without changes
|
@@ -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
|