mongo_mapper-unstable 2009.12.30 → 2010.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +2 -17
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/mongo_mapper/associations/base.rb +19 -10
- data/lib/mongo_mapper/associations/in_array_proxy.rb +137 -0
- data/lib/mongo_mapper/associations/one_proxy.rb +64 -0
- data/lib/mongo_mapper/associations/proxy.rb +7 -4
- data/lib/mongo_mapper/associations.rb +11 -3
- data/lib/mongo_mapper/callbacks.rb +30 -78
- data/lib/mongo_mapper/dirty.rb +5 -24
- data/lib/mongo_mapper/document.rb +117 -144
- data/lib/mongo_mapper/embedded_document.rb +7 -11
- data/lib/mongo_mapper/finder_options.rb +13 -21
- data/lib/mongo_mapper/mongo_mapper.rb +125 -0
- data/lib/mongo_mapper/pagination.rb +12 -1
- data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +1 -0
- data/lib/mongo_mapper/serialization.rb +2 -2
- data/lib/mongo_mapper/serializers/json_serializer.rb +2 -46
- data/lib/mongo_mapper/support.rb +2 -2
- data/lib/mongo_mapper.rb +8 -2
- data/mongo_mapper.gemspec +14 -8
- data/specs.watchr +3 -5
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +8 -0
- data/test/functional/associations/test_belongs_to_proxy.rb +54 -9
- data/test/functional/associations/test_in_array_proxy.rb +309 -0
- data/test/functional/associations/test_many_documents_proxy.rb +103 -53
- data/test/functional/associations/test_many_embedded_proxy.rb +4 -14
- data/test/functional/associations/test_many_polymorphic_proxy.rb +2 -1
- data/test/functional/associations/test_one_proxy.rb +149 -0
- data/test/functional/test_binary.rb +13 -4
- data/test/functional/test_callbacks.rb +1 -5
- data/test/functional/test_dirty.rb +1 -4
- data/test/functional/test_document.rb +576 -640
- data/test/functional/test_embedded_document.rb +7 -20
- data/test/functional/test_modifiers.rb +238 -0
- data/test/functional/test_pagination.rb +1 -3
- data/test/functional/test_string_id_compatibility.rb +3 -8
- data/test/functional/test_validations.rb +13 -75
- data/test/models.rb +1 -1
- data/test/support/timing.rb +1 -1
- data/test/test_helper.rb +28 -0
- data/test/unit/associations/test_base.rb +54 -13
- data/test/unit/associations/test_proxy.rb +12 -0
- data/test/unit/test_document.rb +36 -26
- data/test/unit/test_embedded_document.rb +14 -51
- data/test/unit/test_finder_options.rb +20 -7
- data/test/unit/test_key.rb +1 -4
- data/test/unit/test_pagination.rb +6 -0
- data/test/unit/test_rails_compatibility.rb +4 -1
- data/test/unit/test_serializations.rb +1 -2
- data/test/unit/test_support.rb +4 -0
- data/test/unit/test_time_zones.rb +1 -2
- data/test/unit/test_validations.rb +3 -14
- metadata +12 -6
- data/lib/mongo_mapper/observing.rb +0 -50
- data/test/unit/test_observing.rb +0 -101
@@ -6,7 +6,6 @@ module MongoMapper
|
|
6
6
|
model.class_eval do
|
7
7
|
include EmbeddedDocument
|
8
8
|
include InstanceMethods
|
9
|
-
include Observing
|
10
9
|
include Callbacks
|
11
10
|
include Dirty
|
12
11
|
include RailsCompatibility::Document
|
@@ -19,6 +18,9 @@ module MongoMapper
|
|
19
18
|
end unless respond_to?(:per_page)
|
20
19
|
end
|
21
20
|
|
21
|
+
extra_extensions.each { |extension| model.extend(extension) }
|
22
|
+
extra_inclusions.each { |inclusion| model.send(:include, inclusion) }
|
23
|
+
|
22
24
|
descendants << model
|
23
25
|
end
|
24
26
|
|
@@ -26,6 +28,34 @@ module MongoMapper
|
|
26
28
|
@descendants ||= Set.new
|
27
29
|
end
|
28
30
|
|
31
|
+
def self.append_extensions(*extensions)
|
32
|
+
extra_extensions.concat extensions
|
33
|
+
|
34
|
+
# Add the extension to existing descendants
|
35
|
+
descendants.each do |model|
|
36
|
+
extensions.each { |extension| model.extend(extension) }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# @api private
|
41
|
+
def self.extra_extensions
|
42
|
+
@extra_extensions ||= []
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.append_inclusions(*inclusions)
|
46
|
+
extra_inclusions.concat inclusions
|
47
|
+
|
48
|
+
# Add the inclusion to existing descendants
|
49
|
+
descendants.each do |model|
|
50
|
+
inclusions.each { |inclusion| model.send :include, inclusion }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# @api private
|
55
|
+
def self.extra_inclusions
|
56
|
+
@extra_inclusions ||= []
|
57
|
+
end
|
58
|
+
|
29
59
|
module ClassMethods
|
30
60
|
def key(*args)
|
31
61
|
key = super
|
@@ -43,18 +73,6 @@ module MongoMapper
|
|
43
73
|
MongoMapper.ensure_index(self, keys_to_index, options)
|
44
74
|
end
|
45
75
|
|
46
|
-
# @overload find(:first, options)
|
47
|
-
# @see Document.first
|
48
|
-
#
|
49
|
-
# @overload find(:last, options)
|
50
|
-
# @see Document.last
|
51
|
-
#
|
52
|
-
# @overload find(:all, options)
|
53
|
-
# @see Document.all
|
54
|
-
#
|
55
|
-
# @overload find(ids, options)
|
56
|
-
#
|
57
|
-
# @raise DocumentNotFound raised when no ID or arguments are provided
|
58
76
|
def find!(*args)
|
59
77
|
options = args.extract_options!
|
60
78
|
case args.first
|
@@ -91,45 +109,21 @@ module MongoMapper
|
|
91
109
|
pagination
|
92
110
|
end
|
93
111
|
|
94
|
-
# @param [Hash] options any conditions understood by
|
95
|
-
# FinderOptions.to_mongo_criteria
|
96
|
-
#
|
97
|
-
# @return the first document in the ordered collection as described by
|
98
|
-
# +options+
|
99
|
-
#
|
100
|
-
# @see FinderOptions
|
101
112
|
def first(options={})
|
102
113
|
find_one(options)
|
103
114
|
end
|
104
115
|
|
105
|
-
# @param [Hash] options any conditions understood by
|
106
|
-
# FinderOptions.to_mongo_criteria
|
107
|
-
# @option [String] :order this *mandatory* option describes how to
|
108
|
-
# identify the ordering of the documents in your collection. Note that
|
109
|
-
# the *last* document in this collection will be selected.
|
110
|
-
#
|
111
|
-
# @return the last document in the ordered collection as described by
|
112
|
-
# +options+
|
113
|
-
#
|
114
|
-
# @raise Exception when no <tt>:order</tt> option has been defined
|
115
116
|
def last(options={})
|
116
117
|
raise ':order option must be provided when using last' if options[:order].blank?
|
117
118
|
find_one(options.merge(:order => invert_order_clause(options[:order])))
|
118
119
|
end
|
119
120
|
|
120
|
-
# @param [Hash] options any conditions understood by
|
121
|
-
# FinderOptions.to_mongo_criteria
|
122
|
-
#
|
123
|
-
# @return [Array] all documents in your collection that match the
|
124
|
-
# provided conditions
|
125
|
-
#
|
126
|
-
# @see FinderOptions
|
127
121
|
def all(options={})
|
128
122
|
find_every(options)
|
129
123
|
end
|
130
124
|
|
131
125
|
def find_by_id(id)
|
132
|
-
|
126
|
+
find(id)
|
133
127
|
end
|
134
128
|
|
135
129
|
def count(options={})
|
@@ -140,52 +134,14 @@ module MongoMapper
|
|
140
134
|
!count(options).zero?
|
141
135
|
end
|
142
136
|
|
143
|
-
# @overload create(doc_attributes)
|
144
|
-
# Create a single new document
|
145
|
-
# @param [Hash] doc_attributes key/value pairs to create a new
|
146
|
-
# document
|
147
|
-
#
|
148
|
-
# @overload create(docs_attributes)
|
149
|
-
# Create many new documents
|
150
|
-
# @param [Array<Hash>] provide many Hashes of key/value pairs to create
|
151
|
-
# multiple documents
|
152
|
-
#
|
153
|
-
# @example Creating a single document
|
154
|
-
# MyModel.create({ :foo => "bar" })
|
155
|
-
#
|
156
|
-
# @example Creating multiple documents
|
157
|
-
# MyModel.create([{ :foo => "bar" }, { :foo => "baz" })
|
158
|
-
#
|
159
|
-
# @return [Boolean] when a document is successfully created, +true+ will
|
160
|
-
# be returned. If a document fails to create, +false+ will be returned.
|
161
137
|
def create(*docs)
|
162
138
|
initialize_each(*docs) { |doc| doc.save }
|
163
139
|
end
|
164
140
|
|
165
|
-
# @see Document.create
|
166
|
-
#
|
167
|
-
# @raise [DocumentNotValid] raised if a document fails to create
|
168
141
|
def create!(*docs)
|
169
142
|
initialize_each(*docs) { |doc| doc.save! }
|
170
143
|
end
|
171
144
|
|
172
|
-
# @overload update(id, attributes)
|
173
|
-
# Update a single document
|
174
|
-
# @param id the ID of the document you wish to update
|
175
|
-
# @param [Hash] attributes the key to update on the document with a new
|
176
|
-
# value
|
177
|
-
#
|
178
|
-
# @overload update(ids_and_attributes)
|
179
|
-
# Update multiple documents
|
180
|
-
# @param [Hash] ids_and_attributes each key is the ID of some document
|
181
|
-
# you wish to update. The value each key points toward are those
|
182
|
-
# applied to the target document
|
183
|
-
#
|
184
|
-
# @example Updating single document
|
185
|
-
# Person.update(1, {:foo => 'bar'})
|
186
|
-
#
|
187
|
-
# @example Updating multiple documents at once:
|
188
|
-
# Person.update({'1' => {:foo => 'bar'}, '2' => {:baz => 'wick'}})
|
189
145
|
def update(*args)
|
190
146
|
if args.length == 1
|
191
147
|
update_multiple(args[0])
|
@@ -195,10 +151,6 @@ module MongoMapper
|
|
195
151
|
end
|
196
152
|
end
|
197
153
|
|
198
|
-
# Removes ("deletes") one or many documents from the collection. Note
|
199
|
-
# that this will bypass any +destroy+ hooks defined by your class.
|
200
|
-
#
|
201
|
-
# @param [Array] ids the ID or IDs of the records you wish to delete
|
202
154
|
def delete(*ids)
|
203
155
|
collection.remove(to_criteria(:_id => ids.flatten))
|
204
156
|
end
|
@@ -207,27 +159,6 @@ module MongoMapper
|
|
207
159
|
collection.remove(to_criteria(options))
|
208
160
|
end
|
209
161
|
|
210
|
-
# Iterates over each document found by the provided IDs and calls their
|
211
|
-
# +destroy+ method. This has the advantage of processing your document's
|
212
|
-
# +destroy+ call-backs.
|
213
|
-
#
|
214
|
-
# @overload destroy(id)
|
215
|
-
# Destroy a single document by ID
|
216
|
-
# @param id the ID of the document to destroy
|
217
|
-
#
|
218
|
-
# @overload destroy(ids)
|
219
|
-
# Destroy many documents by their IDs
|
220
|
-
# @param [Array] the IDs of each document you wish to destroy
|
221
|
-
#
|
222
|
-
# @example Destroying a single document
|
223
|
-
# Person.destroy("34")
|
224
|
-
#
|
225
|
-
# @example Destroying multiple documents
|
226
|
-
# Person.destroy("34", "45", ..., "54")
|
227
|
-
#
|
228
|
-
# # OR...
|
229
|
-
#
|
230
|
-
# Person.destroy(["34", "45", ..., "54"])
|
231
162
|
def destroy(*ids)
|
232
163
|
find_some(ids.flatten).each(&:destroy)
|
233
164
|
end
|
@@ -235,15 +166,58 @@ module MongoMapper
|
|
235
166
|
def destroy_all(options={})
|
236
167
|
all(options).each(&:destroy)
|
237
168
|
end
|
169
|
+
|
170
|
+
def increment(*args)
|
171
|
+
modifier_update('$inc', args)
|
172
|
+
end
|
173
|
+
|
174
|
+
def decrement(*args)
|
175
|
+
criteria, keys = criteria_and_keys_from_args(args)
|
176
|
+
values, to_decrement = keys.values, {}
|
177
|
+
keys.keys.each_with_index { |k, i| to_decrement[k] = -values[i].abs }
|
178
|
+
collection.update(criteria, {'$inc' => to_decrement}, :multi => true)
|
179
|
+
end
|
180
|
+
|
181
|
+
def set(*args)
|
182
|
+
modifier_update('$set', args)
|
183
|
+
end
|
184
|
+
|
185
|
+
def push(*args)
|
186
|
+
modifier_update('$push', args)
|
187
|
+
end
|
188
|
+
|
189
|
+
def push_all(*args)
|
190
|
+
modifier_update('$pushAll', args)
|
191
|
+
end
|
192
|
+
|
193
|
+
def push_uniq(*args)
|
194
|
+
criteria, keys = criteria_and_keys_from_args(args)
|
195
|
+
keys.each { |key, value | criteria[key] = {'$ne' => value} }
|
196
|
+
collection.update(criteria, {'$push' => keys}, :multi => true)
|
197
|
+
end
|
198
|
+
|
199
|
+
def pull(*args)
|
200
|
+
modifier_update('$pull', args)
|
201
|
+
end
|
202
|
+
|
203
|
+
def pull_all(*args)
|
204
|
+
modifier_update('$pullAll', args)
|
205
|
+
end
|
206
|
+
|
207
|
+
def modifier_update(modifier, args)
|
208
|
+
criteria, keys = criteria_and_keys_from_args(args)
|
209
|
+
modifiers = {modifier => keys}
|
210
|
+
collection.update(criteria, modifiers, :multi => true)
|
211
|
+
end
|
212
|
+
private :modifier_update
|
213
|
+
|
214
|
+
def criteria_and_keys_from_args(args)
|
215
|
+
keys = args.pop
|
216
|
+
criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
|
217
|
+
[to_criteria(criteria), keys]
|
218
|
+
end
|
219
|
+
private :criteria_and_keys_from_args
|
238
220
|
|
239
|
-
# @overload connection()
|
240
|
-
# @return [Mongo::Connection] the connection used by your document class
|
241
|
-
#
|
242
|
-
# @overload connection(mongo_connection)
|
243
|
-
# @param [Mongo::Connection] mongo_connection a new connection for your
|
244
|
-
# document class to use
|
245
|
-
# @return [Mongo::Connection] a new Mongo::Connection for yoru document
|
246
|
-
# class
|
247
221
|
def connection(mongo_connection=nil)
|
248
222
|
if mongo_connection.nil?
|
249
223
|
@connection ||= MongoMapper.connection
|
@@ -253,24 +227,14 @@ module MongoMapper
|
|
253
227
|
@connection
|
254
228
|
end
|
255
229
|
|
256
|
-
# Changes the database name from the default to whatever you want
|
257
|
-
#
|
258
|
-
# @param [#to_s] name the new database name to use.
|
259
230
|
def set_database_name(name)
|
260
231
|
@database_name = name
|
261
232
|
end
|
262
233
|
|
263
|
-
# Returns the database name
|
264
|
-
#
|
265
|
-
# @return [String] the database name
|
266
234
|
def database_name
|
267
235
|
@database_name
|
268
236
|
end
|
269
237
|
|
270
|
-
# Returns the database the document should use. Defaults to
|
271
|
-
# MongoMapper.database if other database is not set.
|
272
|
-
#
|
273
|
-
# @return [Mongo::DB] the mongo database instance
|
274
238
|
def database
|
275
239
|
if database_name.nil?
|
276
240
|
MongoMapper.database
|
@@ -279,35 +243,31 @@ module MongoMapper
|
|
279
243
|
end
|
280
244
|
end
|
281
245
|
|
282
|
-
# Changes the collection name from the default to whatever you want
|
283
|
-
#
|
284
|
-
# @param [#to_s] name the new collection name to use.
|
285
246
|
def set_collection_name(name)
|
286
247
|
@collection_name = name
|
287
248
|
end
|
288
249
|
|
289
|
-
# Returns the collection name, if not set, defaults to class name tableized
|
290
|
-
#
|
291
|
-
# @return [String] the collection name, if not set, defaults to class
|
292
|
-
# name tableized
|
293
250
|
def collection_name
|
294
251
|
@collection_name ||= self.to_s.tableize.gsub(/\//, '.')
|
295
252
|
end
|
296
253
|
|
297
|
-
# @return the Mongo Ruby driver +collection+ object
|
298
254
|
def collection
|
299
255
|
database.collection(collection_name)
|
300
256
|
end
|
301
|
-
|
302
|
-
# Defines a +created_at+ and +updated_at+ attribute (with a +Time+
|
303
|
-
# value) on your document. These attributes are updated by an
|
304
|
-
# injected +update_timestamps+ +before_save+ hook.
|
257
|
+
|
305
258
|
def timestamps!
|
306
259
|
key :created_at, Time
|
307
260
|
key :updated_at, Time
|
308
261
|
class_eval { before_save :update_timestamps }
|
309
262
|
end
|
310
263
|
|
264
|
+
def userstamps!
|
265
|
+
key :creator_id, ObjectId
|
266
|
+
key :updater_id, ObjectId
|
267
|
+
belongs_to :creator, :class_name => 'User'
|
268
|
+
belongs_to :updater, :class_name => 'User'
|
269
|
+
end
|
270
|
+
|
311
271
|
def single_collection_inherited?
|
312
272
|
keys.has_key?('_type') && single_collection_inherited_superclass?
|
313
273
|
end
|
@@ -406,13 +366,23 @@ module MongoMapper
|
|
406
366
|
def collection
|
407
367
|
self.class.collection
|
408
368
|
end
|
369
|
+
|
370
|
+
def database
|
371
|
+
self.class.database
|
372
|
+
end
|
409
373
|
|
410
374
|
def new?
|
411
375
|
read_attribute('_id').blank? || using_custom_id?
|
412
376
|
end
|
413
377
|
|
414
|
-
def save(
|
415
|
-
|
378
|
+
def save(options={})
|
379
|
+
if options === false
|
380
|
+
ActiveSupport::Deprecation.warn "save with true/false is deprecated. You should now use :validate => true/false."
|
381
|
+
options = {:validate => false}
|
382
|
+
end
|
383
|
+
options.reverse_merge!(:validate => true)
|
384
|
+
perform_validations = options.delete(:validate)
|
385
|
+
!perform_validations || valid? ? create_or_update(options) : false
|
416
386
|
end
|
417
387
|
|
418
388
|
def save!
|
@@ -420,9 +390,11 @@ module MongoMapper
|
|
420
390
|
end
|
421
391
|
|
422
392
|
def destroy
|
423
|
-
|
424
|
-
|
425
|
-
|
393
|
+
self.class.delete(id) unless new?
|
394
|
+
end
|
395
|
+
|
396
|
+
def delete
|
397
|
+
self.class.delete(id) unless new?
|
426
398
|
end
|
427
399
|
|
428
400
|
def reload
|
@@ -433,14 +405,14 @@ module MongoMapper
|
|
433
405
|
end
|
434
406
|
|
435
407
|
private
|
436
|
-
def create_or_update
|
437
|
-
result = new? ? create : update
|
408
|
+
def create_or_update(options={})
|
409
|
+
result = new? ? create(options) : update(options)
|
438
410
|
result != false
|
439
411
|
end
|
440
412
|
|
441
|
-
def create
|
413
|
+
def create(options={})
|
442
414
|
assign_id
|
443
|
-
save_to_collection
|
415
|
+
save_to_collection(options)
|
444
416
|
end
|
445
417
|
|
446
418
|
def assign_id
|
@@ -449,13 +421,14 @@ module MongoMapper
|
|
449
421
|
end
|
450
422
|
end
|
451
423
|
|
452
|
-
def update
|
453
|
-
save_to_collection
|
424
|
+
def update(options={})
|
425
|
+
save_to_collection(options)
|
454
426
|
end
|
455
427
|
|
456
|
-
def save_to_collection
|
428
|
+
def save_to_collection(options={})
|
457
429
|
clear_custom_id_flag
|
458
|
-
|
430
|
+
safe = options.delete(:safe) || false
|
431
|
+
collection.save(to_mongo, :safe => safe)
|
459
432
|
end
|
460
433
|
|
461
434
|
def update_timestamps
|
@@ -281,7 +281,7 @@ module MongoMapper
|
|
281
281
|
end
|
282
282
|
|
283
283
|
def id
|
284
|
-
|
284
|
+
self[:_id]
|
285
285
|
end
|
286
286
|
|
287
287
|
def id=(value)
|
@@ -291,7 +291,7 @@ module MongoMapper
|
|
291
291
|
@using_custom_id = true
|
292
292
|
end
|
293
293
|
|
294
|
-
|
294
|
+
self[:_id] = value
|
295
295
|
end
|
296
296
|
|
297
297
|
def using_custom_id?
|
@@ -305,16 +305,12 @@ module MongoMapper
|
|
305
305
|
"#<#{self.class} #{attributes_as_nice_string}>"
|
306
306
|
end
|
307
307
|
|
308
|
-
def save
|
309
|
-
|
310
|
-
_root_document.save
|
311
|
-
end
|
308
|
+
def save(options={})
|
309
|
+
_root_document.try(:save, options)
|
312
310
|
end
|
313
311
|
|
314
|
-
def save!
|
315
|
-
|
316
|
-
_root_document.save!
|
317
|
-
end
|
312
|
+
def save!(options={})
|
313
|
+
_root_document.try(:save!, options)
|
318
314
|
end
|
319
315
|
|
320
316
|
def update_attributes(attrs={})
|
@@ -355,7 +351,7 @@ module MongoMapper
|
|
355
351
|
def read_attribute(name)
|
356
352
|
if key = _keys[name]
|
357
353
|
value = key.get(instance_variable_get("@#{name}"))
|
358
|
-
instance_variable_set "@#{name}", value
|
354
|
+
instance_variable_set "@#{name}", value
|
359
355
|
value
|
360
356
|
else
|
361
357
|
raise KeyNotFound, "Could not find key: #{name.inspect}"
|
@@ -1,25 +1,20 @@
|
|
1
1
|
module MongoMapper
|
2
|
-
#
|
3
|
-
#
|
4
|
-
# == Important Note
|
5
|
-
#
|
2
|
+
# = Important Note
|
6
3
|
# This class is private to MongoMapper and should not be considered part of
|
7
|
-
# MongoMapper's public API.
|
8
|
-
# useful for understanding how MongoMapper handles the parsing of finder
|
9
|
-
# conditions and options.
|
4
|
+
# MongoMapper's public API.
|
10
5
|
#
|
11
6
|
class FinderOptions
|
12
7
|
OptionKeys = [:fields, :select, :skip, :offset, :limit, :sort, :order]
|
13
|
-
|
8
|
+
|
14
9
|
def self.normalized_field(field)
|
15
10
|
field.to_s == 'id' ? :_id : field
|
16
11
|
end
|
17
|
-
|
12
|
+
|
18
13
|
def self.normalized_order_direction(direction)
|
19
14
|
direction ||= 'ASC'
|
20
15
|
direction.upcase == 'ASC' ? 1 : -1
|
21
16
|
end
|
22
|
-
|
17
|
+
|
23
18
|
def initialize(model, options)
|
24
19
|
raise ArgumentError, "Options must be a hash" unless options.is_a?(Hash)
|
25
20
|
options = options.symbolize_keys
|
@@ -38,15 +33,11 @@ module MongoMapper
|
|
38
33
|
|
39
34
|
add_sci_scope
|
40
35
|
end
|
41
|
-
|
42
|
-
# @return [Hash] Mongo compatible criteria options
|
43
|
-
#
|
44
|
-
# @see FinderOptions#to_mongo_criteria
|
36
|
+
|
45
37
|
def criteria
|
46
38
|
to_mongo_criteria(@conditions)
|
47
39
|
end
|
48
|
-
|
49
|
-
# @return [Hash] Mongo compatible options
|
40
|
+
|
50
41
|
def options
|
51
42
|
fields = @options.delete(:fields) || @options.delete(:select)
|
52
43
|
skip = @options.delete(:skip) || @options.delete(:offset) || 0
|
@@ -55,8 +46,7 @@ module MongoMapper
|
|
55
46
|
|
56
47
|
{:fields => to_mongo_fields(fields), :skip => skip.to_i, :limit => limit.to_i, :sort => sort}
|
57
48
|
end
|
58
|
-
|
59
|
-
# @return [Array<Hash>] Mongo criteria and options enclosed in an Array
|
49
|
+
|
60
50
|
def to_a
|
61
51
|
[criteria, options]
|
62
52
|
end
|
@@ -82,6 +72,8 @@ module MongoMapper
|
|
82
72
|
criteria[field] = operator?(field) ? value : {'$in' => value}
|
83
73
|
when Hash
|
84
74
|
criteria[field] = to_mongo_criteria(value, field)
|
75
|
+
when Time
|
76
|
+
criteria[field] = value.utc
|
85
77
|
else
|
86
78
|
criteria[field] = value
|
87
79
|
end
|
@@ -104,10 +96,10 @@ module MongoMapper
|
|
104
96
|
def to_mongo_fields(fields)
|
105
97
|
return if fields.blank?
|
106
98
|
|
107
|
-
if fields.
|
108
|
-
fields.split(',').map { |field| field.strip }
|
109
|
-
else
|
99
|
+
if fields.respond_to?(:flatten, :compact)
|
110
100
|
fields.flatten.compact
|
101
|
+
else
|
102
|
+
fields.split(',').map { |field| field.strip }
|
111
103
|
end
|
112
104
|
end
|
113
105
|
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# if Gem is defined i'll assume you are using rubygems and lock specific versions
|
2
|
+
# call me crazy but a plain old require will just get the latest version you have installed
|
3
|
+
# so i want to make sure that if you are using gems you do in fact have the correct versions
|
4
|
+
# if there is a better way to do this, please enlighten me!
|
5
|
+
if self.class.const_defined?(:Gem)
|
6
|
+
gem 'activesupport', '>= 2.3'
|
7
|
+
gem 'mongo', '0.18.2'
|
8
|
+
gem 'jnunemaker-validatable', '1.8.1'
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'active_support'
|
12
|
+
require 'mongo'
|
13
|
+
require 'validatable'
|
14
|
+
|
15
|
+
module MongoMapper
|
16
|
+
# generic MM error
|
17
|
+
class MongoMapperError < StandardError; end
|
18
|
+
|
19
|
+
# raised when key expected to exist but not found
|
20
|
+
class KeyNotFound < MongoMapperError; end
|
21
|
+
|
22
|
+
# raised when document expected but not found
|
23
|
+
class DocumentNotFound < MongoMapperError; end
|
24
|
+
|
25
|
+
# raised when document not valid and using !
|
26
|
+
class DocumentNotValid < MongoMapperError
|
27
|
+
def initialize(document)
|
28
|
+
super("Validation failed: #{document.errors.full_messages.join(", ")}")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# @api public
|
33
|
+
def self.connection
|
34
|
+
@@connection ||= Mongo::Connection.new
|
35
|
+
end
|
36
|
+
|
37
|
+
# @api public
|
38
|
+
def self.connection=(new_connection)
|
39
|
+
@@connection = new_connection
|
40
|
+
end
|
41
|
+
|
42
|
+
# @api public
|
43
|
+
def self.logger
|
44
|
+
connection.logger
|
45
|
+
end
|
46
|
+
|
47
|
+
# @api public
|
48
|
+
def self.database=(name)
|
49
|
+
@@database = nil
|
50
|
+
@@database_name = name
|
51
|
+
end
|
52
|
+
|
53
|
+
# @api public
|
54
|
+
def self.database
|
55
|
+
if @@database_name.blank?
|
56
|
+
raise 'You forgot to set the default database name: MongoMapper.database = "foobar"'
|
57
|
+
end
|
58
|
+
|
59
|
+
@@database ||= MongoMapper.connection.db(@@database_name)
|
60
|
+
end
|
61
|
+
|
62
|
+
# @api private
|
63
|
+
def self.ensured_indexes
|
64
|
+
@@ensured_indexes ||= []
|
65
|
+
end
|
66
|
+
|
67
|
+
# @api private
|
68
|
+
def self.ensured_indexes=(value)
|
69
|
+
@@ensured_indexes = value
|
70
|
+
end
|
71
|
+
|
72
|
+
# @api private
|
73
|
+
def self.ensure_index(klass, keys, options={})
|
74
|
+
ensured_indexes << {:klass => klass, :keys => keys, :options => options}
|
75
|
+
end
|
76
|
+
|
77
|
+
# @api public
|
78
|
+
def self.ensure_indexes!
|
79
|
+
ensured_indexes.each do |index|
|
80
|
+
unique = index[:options].delete(:unique)
|
81
|
+
index[:klass].collection.create_index(index[:keys], unique)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# @api private
|
86
|
+
def self.use_time_zone?
|
87
|
+
Time.respond_to?(:zone) && Time.zone ? true : false
|
88
|
+
end
|
89
|
+
|
90
|
+
# @api private
|
91
|
+
def self.time_class
|
92
|
+
use_time_zone? ? Time.zone : Time
|
93
|
+
end
|
94
|
+
|
95
|
+
# @api private
|
96
|
+
def self.normalize_object_id(value)
|
97
|
+
value.is_a?(String) ? Mongo::ObjectID.from_string(value) : value
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
require 'mongo_mapper/support'
|
102
|
+
require 'mongo_mapper/callbacks'
|
103
|
+
require 'mongo_mapper/finder_options'
|
104
|
+
require 'mongo_mapper/dirty'
|
105
|
+
require 'mongo_mapper/dynamic_finder'
|
106
|
+
require 'mongo_mapper/key'
|
107
|
+
require 'mongo_mapper/pagination'
|
108
|
+
require 'mongo_mapper/serialization'
|
109
|
+
require 'mongo_mapper/validations'
|
110
|
+
require 'mongo_mapper/rails_compatibility/document'
|
111
|
+
require 'mongo_mapper/rails_compatibility/embedded_document'
|
112
|
+
require 'mongo_mapper/embedded_document'
|
113
|
+
require 'mongo_mapper/document'
|
114
|
+
require 'mongo_mapper/associations'
|
115
|
+
require 'mongo_mapper/associations/base'
|
116
|
+
require 'mongo_mapper/associations/proxy'
|
117
|
+
require 'mongo_mapper/associations/collection'
|
118
|
+
require 'mongo_mapper/associations/many_documents_proxy'
|
119
|
+
require 'mongo_mapper/associations/belongs_to_proxy'
|
120
|
+
require 'mongo_mapper/associations/belongs_to_polymorphic_proxy'
|
121
|
+
require 'mongo_mapper/associations/many_polymorphic_proxy'
|
122
|
+
require 'mongo_mapper/associations/many_embedded_proxy'
|
123
|
+
require 'mongo_mapper/associations/many_embedded_polymorphic_proxy'
|
124
|
+
require 'mongo_mapper/associations/many_documents_as_proxy'
|
125
|
+
require 'mongo_mapper/associations/one_proxy'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module MongoMapper
|
2
2
|
module Pagination
|
3
3
|
class PaginationProxy
|
4
|
-
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil
|
4
|
+
instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
|
5
5
|
|
6
6
|
attr_accessor :subject
|
7
7
|
attr_reader :total_entries, :per_page, :current_page
|
@@ -33,7 +33,18 @@ module MongoMapper
|
|
33
33
|
(current_page - 1) * per_page
|
34
34
|
end
|
35
35
|
alias offset skip # for will paginate support
|
36
|
+
|
37
|
+
def send(method, *args, &block)
|
38
|
+
if respond_to?(method)
|
39
|
+
super
|
40
|
+
else
|
41
|
+
subject.send(method, *args, &block)
|
42
|
+
end
|
43
|
+
end
|
36
44
|
|
45
|
+
def ===(other)
|
46
|
+
other === subject
|
47
|
+
end
|
37
48
|
|
38
49
|
def method_missing(name, *args, &block)
|
39
50
|
@subject.send(name, *args, &block)
|