mongo_mapper 0.6.8 → 0.6.9
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/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 +61 -0
- data/lib/mongo_mapper/associations/proxy.rb +0 -2
- data/lib/mongo_mapper/associations.rb +5 -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 +42 -30
- 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 +5 -2
- data/lib/mongo_mapper/validations.rb +1 -3
- 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_proxy.rb +43 -0
- 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_polymorphic_proxy.rb +4 -3
- data/test/functional/associations/test_one_proxy.rb +131 -0
- data/test/functional/test_binary.rb +15 -0
- data/test/functional/test_document.rb +581 -631
- data/test/functional/test_modifiers.rb +242 -0
- data/test/functional/test_validations.rb +0 -17
- data/test/models.rb +1 -1
- data/test/support/timing.rb +1 -1
- data/test/unit/associations/test_base.rb +54 -13
- data/test/unit/test_document.rb +32 -0
- data/test/unit/test_embedded_document.rb +0 -9
- data/test/unit/test_finder_options.rb +36 -7
- data/test/unit/test_pagination.rb +6 -0
- data/test/unit/test_rails_compatibility.rb +4 -1
- data/test/unit/test_support.rb +4 -0
- 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,17 +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
|
-
# @private
|
12
6
|
class FinderOptions
|
13
7
|
OptionKeys = [:fields, :select, :skip, :offset, :limit, :sort, :order]
|
14
8
|
|
9
|
+
def self.normalized_field(field)
|
10
|
+
field.to_s == 'id' ? :_id : field
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.normalized_order_direction(direction)
|
14
|
+
direction ||= 'ASC'
|
15
|
+
direction.upcase == 'ASC' ? 1 : -1
|
16
|
+
end
|
17
|
+
|
15
18
|
def initialize(model, options)
|
16
19
|
raise ArgumentError, "Options must be a hash" unless options.is_a?(Hash)
|
17
20
|
options = options.symbolize_keys
|
@@ -30,15 +33,11 @@ module MongoMapper
|
|
30
33
|
|
31
34
|
add_sci_scope
|
32
35
|
end
|
33
|
-
|
34
|
-
# @return [Hash] Mongo compatible criteria options
|
35
|
-
#
|
36
|
-
# @see FinderOptions#to_mongo_criteria
|
36
|
+
|
37
37
|
def criteria
|
38
38
|
to_mongo_criteria(@conditions)
|
39
39
|
end
|
40
|
-
|
41
|
-
# @return [Hash] Mongo compatible options
|
40
|
+
|
42
41
|
def options
|
43
42
|
fields = @options.delete(:fields) || @options.delete(:select)
|
44
43
|
skip = @options.delete(:skip) || @options.delete(:offset) || 0
|
@@ -47,8 +46,7 @@ module MongoMapper
|
|
47
46
|
|
48
47
|
{:fields => to_mongo_fields(fields), :skip => skip.to_i, :limit => limit.to_i, :sort => sort}
|
49
48
|
end
|
50
|
-
|
51
|
-
# @return [Array<Hash>] Mongo criteria and options enclosed in an Array
|
49
|
+
|
52
50
|
def to_a
|
53
51
|
[criteria, options]
|
54
52
|
end
|
@@ -58,14 +56,14 @@ module MongoMapper
|
|
58
56
|
criteria = {}
|
59
57
|
|
60
58
|
conditions.each_pair do |field, value|
|
61
|
-
field = normalized_field(field)
|
59
|
+
field = self.class.normalized_field(field)
|
62
60
|
|
63
61
|
if @model.object_id_key?(field) && value.is_a?(String)
|
64
62
|
value = Mongo::ObjectID.from_string(value)
|
65
63
|
end
|
66
64
|
|
67
65
|
if field.is_a?(FinderOperator)
|
68
|
-
criteria.
|
66
|
+
criteria.update(field.to_criteria(value))
|
69
67
|
next
|
70
68
|
end
|
71
69
|
|
@@ -74,6 +72,8 @@ module MongoMapper
|
|
74
72
|
criteria[field] = operator?(field) ? value : {'$in' => value}
|
75
73
|
when Hash
|
76
74
|
criteria[field] = to_mongo_criteria(value, field)
|
75
|
+
when Time
|
76
|
+
criteria[field] = value.utc
|
77
77
|
else
|
78
78
|
criteria[field] = value
|
79
79
|
end
|
@@ -86,10 +86,6 @@ module MongoMapper
|
|
86
86
|
field.to_s =~ /^\$/
|
87
87
|
end
|
88
88
|
|
89
|
-
def normalized_field(field)
|
90
|
-
field.to_s == 'id' ? :_id : field
|
91
|
-
end
|
92
|
-
|
93
89
|
# adds _type single collection inheritance scope for models that need it
|
94
90
|
def add_sci_scope
|
95
91
|
if @model.single_collection_inherited?
|
@@ -100,23 +96,29 @@ module MongoMapper
|
|
100
96
|
def to_mongo_fields(fields)
|
101
97
|
return if fields.blank?
|
102
98
|
|
103
|
-
if fields.
|
104
|
-
fields.split(',').map { |field| field.strip }
|
105
|
-
else
|
99
|
+
if fields.respond_to?(:flatten, :compact)
|
106
100
|
fields.flatten.compact
|
101
|
+
else
|
102
|
+
fields.split(',').map { |field| field.strip }
|
107
103
|
end
|
108
104
|
end
|
109
105
|
|
110
106
|
def convert_order_to_sort(sort)
|
111
107
|
return if sort.blank?
|
112
|
-
|
113
|
-
|
108
|
+
|
109
|
+
if sort.respond_to?(:all?) && sort.all? { |s| s.respond_to?(:to_order) }
|
110
|
+
sort.map { |s| s.to_order }
|
111
|
+
elsif sort.respond_to?(:to_order)
|
112
|
+
[sort.to_order]
|
113
|
+
else
|
114
|
+
pieces = sort.split(',')
|
115
|
+
pieces.map { |s| to_mongo_sort_piece(s) }
|
116
|
+
end
|
114
117
|
end
|
115
118
|
|
116
119
|
def to_mongo_sort_piece(str)
|
117
120
|
field, direction = str.strip.split(' ')
|
118
|
-
direction
|
119
|
-
direction = direction.upcase == 'ASC' ? 1 : -1
|
121
|
+
direction = FinderOptions.normalized_order_direction(direction)
|
120
122
|
[field, direction]
|
121
123
|
end
|
122
124
|
end
|
@@ -127,7 +129,17 @@ module MongoMapper
|
|
127
129
|
end
|
128
130
|
|
129
131
|
def to_criteria(value)
|
130
|
-
{@field => {@operator => value}}
|
132
|
+
{FinderOptions.normalized_field(@field) => {@operator => value}}
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
class OrderOperator
|
137
|
+
def initialize(field, direction)
|
138
|
+
@field, @direction = field, direction
|
139
|
+
end
|
140
|
+
|
141
|
+
def to_order
|
142
|
+
[@field.to_s, FinderOptions.normalized_order_direction(@direction)]
|
131
143
|
end
|
132
144
|
end
|
133
145
|
end
|