mongo_mapper 0.7.5 → 0.7.6
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_mapper.rb +3 -5
- data/lib/mongo_mapper/document.rb +23 -53
- data/lib/mongo_mapper/plugins/associations.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/base.rb +4 -4
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +1 -1
- data/lib/mongo_mapper/plugins/equality.rb +3 -3
- data/lib/mongo_mapper/plugins/identity_map.rb +8 -7
- data/lib/mongo_mapper/plugins/keys.rb +49 -73
- data/lib/mongo_mapper/plugins/keys/key.rb +44 -0
- data/lib/mongo_mapper/plugins/modifiers.rb +9 -5
- data/lib/mongo_mapper/plugins/pagination/proxy.rb +3 -3
- data/lib/mongo_mapper/plugins/serialization.rb +3 -3
- data/lib/mongo_mapper/plugins/timestamps.rb +1 -1
- data/lib/mongo_mapper/plugins/validations.rb +2 -2
- data/lib/mongo_mapper/query.rb +9 -129
- data/lib/mongo_mapper/support.rb +17 -39
- data/lib/mongo_mapper/version.rb +1 -1
- metadata +54 -140
- data/.gitignore +0 -10
- data/Rakefile +0 -37
- data/mongo_mapper.gemspec +0 -214
- data/performance/read_write.rb +0 -52
- data/specs.watchr +0 -51
- data/test/NOTE_ON_TESTING +0 -1
- data/test/active_model_lint_test.rb +0 -13
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +0 -63
- data/test/functional/associations/test_belongs_to_proxy.rb +0 -101
- data/test/functional/associations/test_in_array_proxy.rb +0 -325
- data/test/functional/associations/test_many_documents_as_proxy.rb +0 -229
- data/test/functional/associations/test_many_documents_proxy.rb +0 -536
- data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +0 -176
- data/test/functional/associations/test_many_embedded_proxy.rb +0 -256
- data/test/functional/associations/test_many_polymorphic_proxy.rb +0 -302
- data/test/functional/associations/test_one_embedded_proxy.rb +0 -68
- data/test/functional/associations/test_one_proxy.rb +0 -196
- data/test/functional/test_associations.rb +0 -44
- data/test/functional/test_binary.rb +0 -27
- data/test/functional/test_callbacks.rb +0 -151
- data/test/functional/test_dirty.rb +0 -163
- data/test/functional/test_document.rb +0 -1219
- data/test/functional/test_embedded_document.rb +0 -210
- data/test/functional/test_identity_map.rb +0 -507
- data/test/functional/test_indexing.rb +0 -44
- data/test/functional/test_logger.rb +0 -20
- data/test/functional/test_modifiers.rb +0 -394
- data/test/functional/test_pagination.rb +0 -93
- data/test/functional/test_protected.rb +0 -163
- data/test/functional/test_string_id_compatibility.rb +0 -67
- data/test/functional/test_timestamps.rb +0 -64
- data/test/functional/test_userstamps.rb +0 -28
- data/test/functional/test_validations.rb +0 -342
- data/test/models.rb +0 -227
- data/test/support/custom_matchers.rb +0 -37
- data/test/support/timing.rb +0 -16
- data/test/test_helper.rb +0 -64
- data/test/unit/associations/test_base.rb +0 -212
- data/test/unit/associations/test_proxy.rb +0 -105
- data/test/unit/serializers/test_json_serializer.rb +0 -202
- data/test/unit/test_descendant_appends.rb +0 -71
- data/test/unit/test_document.rb +0 -225
- data/test/unit/test_dynamic_finder.rb +0 -123
- data/test/unit/test_embedded_document.rb +0 -657
- data/test/unit/test_keys.rb +0 -185
- data/test/unit/test_mongo_mapper.rb +0 -118
- data/test/unit/test_pagination.rb +0 -160
- data/test/unit/test_plugins.rb +0 -50
- data/test/unit/test_query.rb +0 -374
- data/test/unit/test_rails.rb +0 -181
- data/test/unit/test_rails_compatibility.rb +0 -52
- data/test/unit/test_serialization.rb +0 -51
- data/test/unit/test_support.rb +0 -382
- data/test/unit/test_time_zones.rb +0 -39
- data/test/unit/test_validations.rb +0 -544
data/lib/mongo_mapper.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
|
-
# Make sure you have the
|
2
|
-
# gem 'activesupport', '>= 2.3.4'
|
3
|
-
# gem 'mongo', '1.0'
|
4
|
-
# gem 'jnunemaker-validatable', '1.8.4'
|
1
|
+
# Make sure you have the correct versions of the gems (see gemspec) in your load path.
|
5
2
|
require 'set'
|
6
3
|
require 'uri'
|
7
4
|
require 'mongo'
|
5
|
+
require 'plucky'
|
8
6
|
require 'validatable'
|
9
7
|
require 'active_support/all'
|
10
8
|
|
@@ -71,7 +69,7 @@ module MongoMapper
|
|
71
69
|
def self.config_for_environment(environment)
|
72
70
|
env = config[environment]
|
73
71
|
return env if env['uri'].blank?
|
74
|
-
|
72
|
+
|
75
73
|
uri = URI.parse(env['uri'])
|
76
74
|
raise InvalidScheme.new('must be mongodb') unless uri.scheme == 'mongodb'
|
77
75
|
{
|
@@ -45,34 +45,31 @@ module MongoMapper
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def find(*args)
|
48
|
-
assert_no_first_last_or_all(args)
|
49
48
|
options = args.extract_options!
|
50
49
|
return nil if args.size == 0
|
51
50
|
|
52
51
|
if args.first.is_a?(Array) || args.size > 1
|
53
52
|
find_some(args, options)
|
54
53
|
else
|
55
|
-
|
54
|
+
query = query(options).update(:_id => args[0])
|
55
|
+
find_one(query.to_hash)
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
def find!(*args)
|
60
|
-
assert_no_first_last_or_all(args)
|
61
60
|
options = args.extract_options!
|
62
61
|
raise DocumentNotFound, "Couldn't find without an ID" if args.size == 0
|
63
62
|
|
64
63
|
if args.first.is_a?(Array) || args.size > 1
|
65
64
|
find_some!(args, options)
|
66
65
|
else
|
67
|
-
|
66
|
+
query = query(options).update(:_id => args[0])
|
67
|
+
find_one(query.to_hash) || raise(DocumentNotFound, "Document match #{options.inspect} does not exist in #{collection.name} collection")
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
71
|
def find_each(options={})
|
72
|
-
|
73
|
-
collection.find(criteria, options).each do |doc|
|
74
|
-
yield load(doc)
|
75
|
-
end
|
72
|
+
query(options).find().each { |doc| yield load(doc) }
|
76
73
|
end
|
77
74
|
|
78
75
|
def find_by_id(id)
|
@@ -93,7 +90,7 @@ module MongoMapper
|
|
93
90
|
|
94
91
|
def last(options={})
|
95
92
|
raise ':order option must be provided when using last' if options[:order].blank?
|
96
|
-
find_one(
|
93
|
+
find_one(query(options).reverse.to_hash)
|
97
94
|
end
|
98
95
|
|
99
96
|
def all(options={})
|
@@ -101,7 +98,7 @@ module MongoMapper
|
|
101
98
|
end
|
102
99
|
|
103
100
|
def count(options={})
|
104
|
-
|
101
|
+
query(options).count
|
105
102
|
end
|
106
103
|
|
107
104
|
def exists?(options={})
|
@@ -126,11 +123,11 @@ module MongoMapper
|
|
126
123
|
end
|
127
124
|
|
128
125
|
def delete(*ids)
|
129
|
-
|
126
|
+
query(:_id => ids.flatten).remove
|
130
127
|
end
|
131
128
|
|
132
129
|
def delete_all(options={})
|
133
|
-
|
130
|
+
query(options).remove
|
134
131
|
end
|
135
132
|
|
136
133
|
def destroy(*ids)
|
@@ -153,6 +150,11 @@ module MongoMapper
|
|
153
150
|
superclass.respond_to?(:keys) && superclass.keys.key?(:_type)
|
154
151
|
end
|
155
152
|
|
153
|
+
# @api private for now
|
154
|
+
def query(options={})
|
155
|
+
Query.new(self, options)
|
156
|
+
end
|
157
|
+
|
156
158
|
private
|
157
159
|
def initialize_each(*docs)
|
158
160
|
instances = []
|
@@ -165,15 +167,9 @@ module MongoMapper
|
|
165
167
|
instances.size == 1 ? instances[0] : instances
|
166
168
|
end
|
167
169
|
|
168
|
-
def assert_no_first_last_or_all(args)
|
169
|
-
if args[0] == :first || args[0] == :last || args[0] == :all
|
170
|
-
raise ArgumentError, "#{self}.find(:#{args}) is no longer supported, use #{self}.#{args} instead."
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
170
|
def find_some(ids, options={})
|
175
|
-
|
176
|
-
find_many(
|
171
|
+
query = query(options).update(:_id => ids.flatten.compact.uniq)
|
172
|
+
find_many(query.to_hash).compact
|
177
173
|
end
|
178
174
|
|
179
175
|
def find_some!(ids, options={})
|
@@ -189,30 +185,12 @@ module MongoMapper
|
|
189
185
|
|
190
186
|
# All query methods that load documents pass through find_one or find_many
|
191
187
|
def find_one(options={})
|
192
|
-
|
193
|
-
if doc = collection.find_one(criteria, options)
|
194
|
-
load(doc)
|
195
|
-
end
|
188
|
+
load(query(options).first)
|
196
189
|
end
|
197
190
|
|
198
191
|
# All query methods that load documents pass through find_one or find_many
|
199
192
|
def find_many(options)
|
200
|
-
|
201
|
-
collection.find(criteria, options).to_a.map do |doc|
|
202
|
-
load(doc)
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
def invert_order_clause(order)
|
207
|
-
order.split(',').map do |order_segment|
|
208
|
-
if order_segment =~ /\sasc/i
|
209
|
-
order_segment.sub /\sasc/i, ' desc'
|
210
|
-
elsif order_segment =~ /\sdesc/i
|
211
|
-
order_segment.sub /\sdesc/i, ' asc'
|
212
|
-
else
|
213
|
-
"#{order_segment.strip} desc"
|
214
|
-
end
|
215
|
-
end.join(',')
|
193
|
+
query(options).all().map { |doc| load(doc) }
|
216
194
|
end
|
217
195
|
|
218
196
|
def update_single(id, attrs)
|
@@ -220,9 +198,9 @@ module MongoMapper
|
|
220
198
|
raise ArgumentError, "Updating a single document requires an id and a hash of attributes"
|
221
199
|
end
|
222
200
|
|
223
|
-
|
224
|
-
|
225
|
-
|
201
|
+
find(id).tap do |doc|
|
202
|
+
doc.update_attributes(attrs)
|
203
|
+
end
|
226
204
|
end
|
227
205
|
|
228
206
|
def update_multiple(docs)
|
@@ -234,14 +212,6 @@ module MongoMapper
|
|
234
212
|
docs.each_pair { |id, attrs| instances << update(id, attrs) }
|
235
213
|
instances
|
236
214
|
end
|
237
|
-
|
238
|
-
def to_criteria(options={})
|
239
|
-
Query.new(self, options).criteria
|
240
|
-
end
|
241
|
-
|
242
|
-
def to_query(options={})
|
243
|
-
Query.new(self, options).to_a
|
244
|
-
end
|
245
215
|
end
|
246
216
|
|
247
217
|
module InstanceMethods
|
@@ -274,9 +244,9 @@ module MongoMapper
|
|
274
244
|
end
|
275
245
|
|
276
246
|
def reload
|
277
|
-
if
|
247
|
+
if doc = self.class.query(:_id => id).first
|
278
248
|
self.class.associations.each { |name, assoc| send(name).reset if respond_to?(name) }
|
279
|
-
self.attributes =
|
249
|
+
self.attributes = doc
|
280
250
|
self
|
281
251
|
else
|
282
252
|
raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
|
@@ -16,8 +16,8 @@ module MongoMapper
|
|
16
16
|
|
17
17
|
def class_name
|
18
18
|
return @class_name if defined?(@class_name)
|
19
|
-
|
20
|
-
@class_name =
|
19
|
+
|
20
|
+
@class_name =
|
21
21
|
if cn = options[:class_name]
|
22
22
|
cn
|
23
23
|
elsif many?
|
@@ -78,8 +78,8 @@ module MongoMapper
|
|
78
78
|
# hate this, need to revisit
|
79
79
|
def proxy_class
|
80
80
|
return @proxy_class if defined?(@proxy_class)
|
81
|
-
|
82
|
-
@proxy_class =
|
81
|
+
|
82
|
+
@proxy_class =
|
83
83
|
if many?
|
84
84
|
if klass.embeddable?
|
85
85
|
polymorphic? ? ManyEmbeddedPolymorphicProxy : ManyEmbeddedProxy
|
@@ -8,7 +8,7 @@ module MongoMapper
|
|
8
8
|
def self.clear
|
9
9
|
models.each { |m| m.identity_map.clear }
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def self.configure(model)
|
13
13
|
IdentityMap.models << model
|
14
14
|
end
|
@@ -28,27 +28,28 @@ module MongoMapper
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def find_one(options={})
|
31
|
-
|
32
|
-
|
31
|
+
query = query(options)
|
32
|
+
criteria = query.criteria.to_hash
|
33
|
+
|
33
34
|
if simple_find?(criteria) && identity_map.key?(criteria[:_id])
|
34
35
|
identity_map[criteria[:_id]]
|
35
36
|
else
|
36
37
|
super.tap do |document|
|
37
|
-
remove_documents_from_map(document) if selecting_fields?(
|
38
|
+
remove_documents_from_map(document) if selecting_fields?(query.options)
|
38
39
|
end
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
43
|
def find_many(options)
|
43
|
-
criteria, query_options = to_query(options)
|
44
44
|
super.tap do |documents|
|
45
|
-
remove_documents_from_map(documents) if selecting_fields?(
|
45
|
+
remove_documents_from_map(documents) if selecting_fields?(query(options).options)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
def load(attrs)
|
50
|
+
return nil if attrs.nil?
|
50
51
|
document = identity_map[attrs['_id']]
|
51
|
-
|
52
|
+
|
52
53
|
if document.nil? || identity_map_off?
|
53
54
|
document = super
|
54
55
|
identity_map[document._id] = document if identity_map_on?
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module MongoMapper
|
2
2
|
module Plugins
|
3
3
|
module Keys
|
4
|
+
autoload :Key, 'mongo_mapper/plugins/keys/key'
|
5
|
+
|
4
6
|
def self.configure(model)
|
5
7
|
model.key :_id, ObjectId
|
6
8
|
end
|
@@ -17,15 +19,13 @@ module MongoMapper
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def key(*args)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
key
|
22
|
+
Key.new(*args).tap do |key|
|
23
|
+
keys[key.name] = key
|
24
|
+
create_accessors_for(key)
|
25
|
+
create_key_in_descendants(*args)
|
26
|
+
create_indexes_for(key)
|
27
|
+
create_validations_for(key)
|
28
|
+
end
|
29
29
|
end
|
30
30
|
|
31
31
|
def key?(key)
|
@@ -36,9 +36,12 @@ module MongoMapper
|
|
36
36
|
object_id_key?(:_id)
|
37
37
|
end
|
38
38
|
|
39
|
+
def object_id_keys
|
40
|
+
keys.keys.select { |key| keys[key].type == ObjectId }.map(&:to_sym)
|
41
|
+
end
|
42
|
+
|
39
43
|
def object_id_key?(name)
|
40
|
-
|
41
|
-
key && key.type == ObjectId
|
44
|
+
object_id_keys.include?(name.to_sym)
|
42
45
|
end
|
43
46
|
|
44
47
|
def to_mongo(instance)
|
@@ -53,6 +56,7 @@ module MongoMapper
|
|
53
56
|
|
54
57
|
# load is overridden in identity map to ensure same objects are loaded
|
55
58
|
def load(attrs)
|
59
|
+
return nil if attrs.nil?
|
56
60
|
begin
|
57
61
|
klass = attrs['_type'].present? ? attrs['_type'].constantize : self
|
58
62
|
klass.new(attrs, true)
|
@@ -62,14 +66,16 @@ module MongoMapper
|
|
62
66
|
end
|
63
67
|
|
64
68
|
private
|
65
|
-
def
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
69
|
+
def key_accessors_module_defined?
|
70
|
+
if method(:const_defined?).arity == 1 # Ruby 1.9 compat check
|
71
|
+
const_defined?('MongoMapperKeys')
|
72
|
+
else
|
73
|
+
const_defined?('MongoMapperKeys', false)
|
74
|
+
end
|
75
|
+
end
|
71
76
|
|
72
|
-
|
77
|
+
def accessors_module
|
78
|
+
if key_accessors_module_defined?
|
73
79
|
const_get 'MongoMapperKeys'
|
74
80
|
else
|
75
81
|
const_set 'MongoMapperKeys', Module.new
|
@@ -154,7 +160,7 @@ module MongoMapper
|
|
154
160
|
|
155
161
|
if from_database
|
156
162
|
@new = false
|
157
|
-
|
163
|
+
load_from_database(attrs)
|
158
164
|
else
|
159
165
|
@new = true
|
160
166
|
assign(attrs)
|
@@ -170,13 +176,11 @@ module MongoMapper
|
|
170
176
|
def attributes=(attrs)
|
171
177
|
return if attrs.blank?
|
172
178
|
|
173
|
-
attrs.each_pair do |
|
174
|
-
|
175
|
-
|
176
|
-
if respond_to?(writer_method)
|
177
|
-
self.send(writer_method, value)
|
179
|
+
attrs.each_pair do |key, value|
|
180
|
+
if respond_to?(:"#{key}=")
|
181
|
+
self.send(:"#{key}=", value)
|
178
182
|
else
|
179
|
-
self[
|
183
|
+
self[key] = value
|
180
184
|
end
|
181
185
|
end
|
182
186
|
end
|
@@ -255,6 +259,17 @@ module MongoMapper
|
|
255
259
|
end
|
256
260
|
|
257
261
|
private
|
262
|
+
def load_from_database(attrs)
|
263
|
+
return if attrs.blank?
|
264
|
+
attrs.each do |key, value|
|
265
|
+
if respond_to?(:"#{key}=") && !self.class.key?(key)
|
266
|
+
self.send(:"#{key}=", value)
|
267
|
+
else
|
268
|
+
self[key] = value
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
258
273
|
def default_id_value(attrs)
|
259
274
|
unless attrs.nil?
|
260
275
|
provided_keys = attrs.keys.map { |k| k.to_s }
|
@@ -278,68 +293,29 @@ module MongoMapper
|
|
278
293
|
end
|
279
294
|
end
|
280
295
|
|
281
|
-
def read_key(
|
282
|
-
if key = keys[
|
283
|
-
|
284
|
-
value = key.get(instance_variable_get(var_name))
|
296
|
+
def read_key(key_name)
|
297
|
+
if key = keys[key_name]
|
298
|
+
value = key.get(instance_variable_get(:"@#{key_name}"))
|
285
299
|
set_parent_document(key, value)
|
286
|
-
instance_variable_set(
|
300
|
+
instance_variable_set(:"@#{key_name}", value)
|
287
301
|
else
|
288
|
-
raise KeyNotFound, "Could not find key: #{
|
302
|
+
raise KeyNotFound, "Could not find key: #{key_name.inspect}"
|
289
303
|
end
|
290
304
|
end
|
291
305
|
|
292
306
|
def read_key_before_typecast(name)
|
293
|
-
instance_variable_get("@#{name}_before_typecast")
|
307
|
+
instance_variable_get(:"@#{name}_before_typecast")
|
294
308
|
end
|
295
309
|
|
296
310
|
def write_key(name, value)
|
297
|
-
key = keys[name]
|
298
|
-
|
311
|
+
key = keys[name.to_s]
|
299
312
|
set_parent_document(key, value)
|
300
|
-
instance_variable_set "@#{name}_before_typecast", value
|
301
|
-
instance_variable_set "@#{name}", key.set(value)
|
313
|
+
instance_variable_set :"@#{name}_before_typecast", value
|
314
|
+
instance_variable_set :"@#{name}", key.set(value)
|
302
315
|
end
|
303
316
|
end
|
304
317
|
|
305
|
-
class Key
|
306
|
-
attr_accessor :name, :type, :options, :default_value
|
307
|
-
|
308
|
-
def initialize(*args)
|
309
|
-
options = args.extract_options!
|
310
|
-
@name, @type = args.shift.to_s, args.shift
|
311
|
-
self.options = (options || {}).symbolize_keys
|
312
|
-
self.default_value = self.options.delete(:default)
|
313
|
-
end
|
314
|
-
|
315
|
-
def ==(other)
|
316
|
-
@name == other.name && @type == other.type
|
317
|
-
end
|
318
|
-
|
319
|
-
def embeddable?
|
320
|
-
type.respond_to?(:embeddable?) && type.embeddable? ? true : false
|
321
|
-
end
|
322
|
-
|
323
|
-
def number?
|
324
|
-
[Integer, Float].include?(type)
|
325
|
-
end
|
326
318
|
|
327
|
-
def get(value)
|
328
|
-
if value.nil? && !default_value.nil?
|
329
|
-
if default_value.respond_to?(:call)
|
330
|
-
return default_value.call
|
331
|
-
else
|
332
|
-
return default_value
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
type.from_mongo(value)
|
337
|
-
end
|
338
|
-
|
339
|
-
def set(value)
|
340
|
-
type.to_mongo(value)
|
341
|
-
end
|
342
|
-
end
|
343
319
|
end
|
344
320
|
end
|
345
321
|
end
|