mongo_mapper 0.7.5 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/lib/mongo_mapper.rb +3 -5
  2. data/lib/mongo_mapper/document.rb +23 -53
  3. data/lib/mongo_mapper/plugins/associations.rb +1 -1
  4. data/lib/mongo_mapper/plugins/associations/base.rb +4 -4
  5. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +1 -1
  6. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +1 -1
  7. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +1 -1
  8. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +1 -1
  9. data/lib/mongo_mapper/plugins/equality.rb +3 -3
  10. data/lib/mongo_mapper/plugins/identity_map.rb +8 -7
  11. data/lib/mongo_mapper/plugins/keys.rb +49 -73
  12. data/lib/mongo_mapper/plugins/keys/key.rb +44 -0
  13. data/lib/mongo_mapper/plugins/modifiers.rb +9 -5
  14. data/lib/mongo_mapper/plugins/pagination/proxy.rb +3 -3
  15. data/lib/mongo_mapper/plugins/serialization.rb +3 -3
  16. data/lib/mongo_mapper/plugins/timestamps.rb +1 -1
  17. data/lib/mongo_mapper/plugins/validations.rb +2 -2
  18. data/lib/mongo_mapper/query.rb +9 -129
  19. data/lib/mongo_mapper/support.rb +17 -39
  20. data/lib/mongo_mapper/version.rb +1 -1
  21. metadata +54 -140
  22. data/.gitignore +0 -10
  23. data/Rakefile +0 -37
  24. data/mongo_mapper.gemspec +0 -214
  25. data/performance/read_write.rb +0 -52
  26. data/specs.watchr +0 -51
  27. data/test/NOTE_ON_TESTING +0 -1
  28. data/test/active_model_lint_test.rb +0 -13
  29. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +0 -63
  30. data/test/functional/associations/test_belongs_to_proxy.rb +0 -101
  31. data/test/functional/associations/test_in_array_proxy.rb +0 -325
  32. data/test/functional/associations/test_many_documents_as_proxy.rb +0 -229
  33. data/test/functional/associations/test_many_documents_proxy.rb +0 -536
  34. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +0 -176
  35. data/test/functional/associations/test_many_embedded_proxy.rb +0 -256
  36. data/test/functional/associations/test_many_polymorphic_proxy.rb +0 -302
  37. data/test/functional/associations/test_one_embedded_proxy.rb +0 -68
  38. data/test/functional/associations/test_one_proxy.rb +0 -196
  39. data/test/functional/test_associations.rb +0 -44
  40. data/test/functional/test_binary.rb +0 -27
  41. data/test/functional/test_callbacks.rb +0 -151
  42. data/test/functional/test_dirty.rb +0 -163
  43. data/test/functional/test_document.rb +0 -1219
  44. data/test/functional/test_embedded_document.rb +0 -210
  45. data/test/functional/test_identity_map.rb +0 -507
  46. data/test/functional/test_indexing.rb +0 -44
  47. data/test/functional/test_logger.rb +0 -20
  48. data/test/functional/test_modifiers.rb +0 -394
  49. data/test/functional/test_pagination.rb +0 -93
  50. data/test/functional/test_protected.rb +0 -163
  51. data/test/functional/test_string_id_compatibility.rb +0 -67
  52. data/test/functional/test_timestamps.rb +0 -64
  53. data/test/functional/test_userstamps.rb +0 -28
  54. data/test/functional/test_validations.rb +0 -342
  55. data/test/models.rb +0 -227
  56. data/test/support/custom_matchers.rb +0 -37
  57. data/test/support/timing.rb +0 -16
  58. data/test/test_helper.rb +0 -64
  59. data/test/unit/associations/test_base.rb +0 -212
  60. data/test/unit/associations/test_proxy.rb +0 -105
  61. data/test/unit/serializers/test_json_serializer.rb +0 -202
  62. data/test/unit/test_descendant_appends.rb +0 -71
  63. data/test/unit/test_document.rb +0 -225
  64. data/test/unit/test_dynamic_finder.rb +0 -123
  65. data/test/unit/test_embedded_document.rb +0 -657
  66. data/test/unit/test_keys.rb +0 -185
  67. data/test/unit/test_mongo_mapper.rb +0 -118
  68. data/test/unit/test_pagination.rb +0 -160
  69. data/test/unit/test_plugins.rb +0 -50
  70. data/test/unit/test_query.rb +0 -374
  71. data/test/unit/test_rails.rb +0 -181
  72. data/test/unit/test_rails_compatibility.rb +0 -52
  73. data/test/unit/test_serialization.rb +0 -51
  74. data/test/unit/test_support.rb +0 -382
  75. data/test/unit/test_time_zones.rb +0 -39
  76. data/test/unit/test_validations.rb +0 -544
@@ -1,10 +1,8 @@
1
- # Make sure you have the following libs in your load path or you could have issues:
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
- find_one(options.merge({:_id => args[0]}))
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
- find_one(options.merge({:_id => args[0]})) || raise(DocumentNotFound, "Document match #{options.inspect} does not exist in #{collection.name} collection")
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
- criteria, options = to_query(options)
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(options.merge(:order => invert_order_clause(options[:order])))
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
- collection.find(to_criteria(options)).count
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
- collection.remove(to_criteria(:_id => ids.flatten))
126
+ query(:_id => ids.flatten).remove
130
127
  end
131
128
 
132
129
  def delete_all(options={})
133
- collection.remove(to_criteria(options))
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
- ids = ids.flatten.compact.uniq
176
- find_many(options.merge(:_id => ids)).compact
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
- criteria, options = to_query(options)
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
- criteria, options = to_query(options)
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
- doc = find(id)
224
- doc.update_attributes(attrs)
225
- doc
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 attrs = collection.find_one({:_id => _id})
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 = attrs
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"
@@ -84,7 +84,7 @@ module MongoMapper
84
84
 
85
85
  proxy
86
86
  end
87
-
87
+
88
88
  def save_to_collection(options = {})
89
89
  super
90
90
  associations.each do |association_name, association|
@@ -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
@@ -3,7 +3,7 @@ module MongoMapper
3
3
  module Associations
4
4
  class BelongsToPolymorphicProxy < Proxy
5
5
  undef_method :object_id
6
-
6
+
7
7
  def replace(doc)
8
8
  if doc
9
9
  doc.save if doc.new?
@@ -3,7 +3,7 @@ module MongoMapper
3
3
  module Associations
4
4
  class BelongsToProxy < Proxy
5
5
  undef_method :object_id
6
-
6
+
7
7
  def replace(doc)
8
8
  if doc
9
9
  doc.save if doc.new?
@@ -88,7 +88,7 @@ module MongoMapper
88
88
  end
89
89
  reset
90
90
  end
91
-
91
+
92
92
  def save_to_collection(options = {})
93
93
  @target.each { |doc| doc.save(options) } if @target
94
94
  end
@@ -3,7 +3,7 @@ module MongoMapper
3
3
  module Associations
4
4
  class OneProxy < Proxy
5
5
  undef_method :object_id
6
-
6
+
7
7
  def build(attrs={})
8
8
  instantiate_target(:new, attrs)
9
9
  end
@@ -5,15 +5,15 @@ module MongoMapper
5
5
  def ==(other)
6
6
  other.is_a?(self.class) && _id == other._id
7
7
  end
8
-
8
+
9
9
  def eql?(other)
10
10
  self == other
11
11
  end
12
-
12
+
13
13
  def equal?(other)
14
14
  object_id === other.object_id
15
15
  end
16
-
16
+
17
17
  def hash
18
18
  _id.hash
19
19
  end
@@ -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
- criteria, query_options = to_query(options)
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?(query_options)
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?(query_options)
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
- key = Key.new(*args)
21
- keys[key.name] = key
22
-
23
- create_accessors_for(key)
24
- create_key_in_descendants(*args)
25
- create_indexes_for(key)
26
- create_validations_for(key)
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
- key = keys[name.to_s]
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 accessors_module
66
- module_defined = if method(:const_defined?).arity == 1 # Ruby 1.9 compat check
67
- const_defined?('MongoMapperKeys')
68
- else
69
- const_defined?('MongoMapperKeys', false)
70
- end
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
- if module_defined
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
- self.attributes = attrs
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 |name, value|
174
- writer_method = "#{name}="
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[name.to_s] = value
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(name)
282
- if key = keys[name]
283
- var_name = "@#{name}"
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(var_name, value)
300
+ instance_variable_set(:"@#{key_name}", value)
287
301
  else
288
- raise KeyNotFound, "Could not find key: #{name.inspect}"
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