mongo_mapper-unstable 2009.11.8 → 2009.11.18

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.
Files changed (42) hide show
  1. data/Rakefile +3 -3
  2. data/VERSION +1 -1
  3. data/bin/mmconsole +10 -5
  4. data/lib/mongo_mapper.rb +28 -5
  5. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +1 -1
  6. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +1 -1
  7. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +2 -2
  8. data/lib/mongo_mapper/associations/many_documents_proxy.rb +2 -2
  9. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +2 -1
  10. data/lib/mongo_mapper/document.rb +3 -12
  11. data/lib/mongo_mapper/embedded_document.rb +37 -19
  12. data/lib/mongo_mapper/finder_options.rb +17 -11
  13. data/lib/mongo_mapper/rails_compatibility/document.rb +4 -0
  14. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +4 -0
  15. data/lib/mongo_mapper/serializers/json_serializer.rb +2 -2
  16. data/lib/mongo_mapper/support.rb +16 -44
  17. data/lib/mongo_mapper/types.rb +64 -0
  18. data/lib/mongo_mapper/validations.rb +1 -1
  19. data/mongo_mapper.gemspec +15 -12
  20. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +10 -10
  21. data/test/functional/associations/test_belongs_to_proxy.rb +2 -1
  22. data/test/functional/associations/test_many_documents_as_proxy.rb +13 -12
  23. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +34 -34
  24. data/test/functional/associations/test_many_embedded_proxy.rb +22 -22
  25. data/test/functional/associations/test_many_polymorphic_proxy.rb +10 -10
  26. data/test/functional/associations/test_many_proxy.rb +14 -15
  27. data/test/functional/test_associations.rb +4 -4
  28. data/test/functional/test_binary.rb +1 -1
  29. data/test/functional/test_dirty.rb +6 -6
  30. data/test/functional/test_document.rb +64 -65
  31. data/test/functional/test_embedded_document.rb +34 -14
  32. data/test/functional/test_string_id_compatibility.rb +72 -0
  33. data/test/functional/test_validations.rb +1 -1
  34. data/test/models.rb +24 -24
  35. data/test/unit/test_document.rb +7 -4
  36. data/test/unit/test_embedded_document.rb +47 -5
  37. data/test/unit/test_finder_options.rb +22 -3
  38. data/test/unit/test_mongo_mapper.rb +65 -0
  39. data/test/unit/test_rails_compatibility.rb +14 -0
  40. data/test/unit/test_support.rb +45 -0
  41. metadata +8 -5
  42. data/test/unit/test_mongomapper.rb +0 -28
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ Jeweler::Tasks.new do |gem|
12
12
  gem.authors = ["John Nunemaker"]
13
13
 
14
14
  gem.add_dependency('activesupport', '>= 2.3')
15
- gem.add_dependency('mongo', '0.16')
15
+ gem.add_dependency('mongo', '0.17.1')
16
16
  gem.add_dependency('jnunemaker-validatable', '1.8.1')
17
17
 
18
18
  gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
@@ -51,5 +51,5 @@ task :default => :test
51
51
  task :test => :check_dependencies
52
52
 
53
53
  YARD::Rake::YardocTask.new(:doc) do |t|
54
- t.options = ["--legacy"]
55
- end
54
+ t.options = ["--legacy"] if RUBY_VERSION < "1.9.0"
55
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2009.11.08
1
+ 2009.11.18
data/bin/mmconsole CHANGED
@@ -1,8 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
- $:.unshift File.dirname(__FILE__)+"/../lib"
3
-
4
- require 'mongo_mapper'
5
- require 'irb'
2
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
3
+
4
+ begin
5
+ require 'mongo_mapper'
6
+ require 'irb'
7
+ rescue LoadError
8
+ require 'rubygems'
9
+ retry
10
+ end
6
11
 
7
12
  IRB.setup(nil)
8
13
  irb = IRB::Irb.new
@@ -43,12 +48,12 @@ Example 2:
43
48
 
44
49
  all_things = Thing.all
45
50
  puts all_things.map { |object| object.name }.inspect
46
-
47
51
  @
48
52
 
49
53
  trap("SIGINT") do
50
54
  irb.signal_handle
51
55
  end
56
+
52
57
  catch(:IRB_EXIT) do
53
58
  irb.eval_input
54
59
  end
data/lib/mongo_mapper.rb CHANGED
@@ -15,28 +15,32 @@ module MongoMapper
15
15
  # raised when document not valid and using !
16
16
  class DocumentNotValid < MongoMapperError
17
17
  def initialize(document)
18
- @document = document
19
- super("Validation failed: #{@document.errors.full_messages.join(", ")}")
18
+ super("Validation failed: #{document.errors.full_messages.join(", ")}")
20
19
  end
21
20
  end
22
21
 
22
+ # @api public
23
23
  def self.connection
24
24
  @@connection ||= Mongo::Connection.new
25
25
  end
26
-
26
+
27
+ # @api public
27
28
  def self.connection=(new_connection)
28
29
  @@connection = new_connection
29
30
  end
30
31
 
32
+ # @api public
31
33
  def self.logger
32
34
  connection.logger
33
35
  end
34
-
36
+
37
+ # @api public
35
38
  def self.database=(name)
36
39
  @@database = nil
37
40
  @@database_name = name
38
41
  end
39
-
42
+
43
+ # @api public
40
44
  def self.database
41
45
  if @@database_name.blank?
42
46
  raise 'You forgot to set the default database name: MongoMapper.database = "foobar"'
@@ -45,14 +49,17 @@ module MongoMapper
45
49
  @@database ||= MongoMapper.connection.db(@@database_name)
46
50
  end
47
51
 
52
+ # @api private
48
53
  def self.ensured_indexes
49
54
  @@ensured_indexes ||= []
50
55
  end
51
56
 
57
+ # @api private
52
58
  def self.ensure_index(klass, keys, options={})
53
59
  ensured_indexes << {:klass => klass, :keys => keys, :options => options}
54
60
  end
55
61
 
62
+ # @api public
56
63
  def self.ensure_indexes!
57
64
  ensured_indexes.each do |index|
58
65
  unique = index[:options].delete(:unique)
@@ -60,6 +67,7 @@ module MongoMapper
60
67
  end
61
68
  end
62
69
 
70
+ # @api private
63
71
  module Finders
64
72
  def dynamic_find(finder, args)
65
73
  attributes = {}
@@ -83,9 +91,24 @@ module MongoMapper
83
91
  end
84
92
  end
85
93
  end
94
+
95
+ # @api private
96
+ def self.use_time_zone?
97
+ Time.respond_to?(:zone) && Time.zone ? true : false
98
+ end
99
+
100
+ # @api private
101
+ def self.time_class
102
+ use_time_zone? ? Time.zone : Time
103
+ end
104
+
105
+ def self.normalize_object_id(value)
106
+ value.is_a?(String) ? Mongo::ObjectID.from_string(value) : value
107
+ end
86
108
  end
87
109
 
88
110
  require 'mongo_mapper/support'
111
+ require 'mongo_mapper/types'
89
112
  require 'mongo_mapper/associations'
90
113
  require 'mongo_mapper/associations/base'
91
114
  require 'mongo_mapper/associations/proxy'
@@ -4,7 +4,7 @@ module MongoMapper
4
4
  def replace(doc)
5
5
  if doc
6
6
  doc.save if doc.new?
7
- id, type = doc.id, doc.class.name
7
+ id, type = doc._id, doc.class.name
8
8
  end
9
9
 
10
10
  @owner.send("#{@association.foreign_key}=", id)
@@ -4,7 +4,7 @@ module MongoMapper
4
4
  def replace(doc)
5
5
  if doc
6
6
  doc.save if doc.new?
7
- id = doc.id
7
+ id = doc._id
8
8
  end
9
9
 
10
10
  @owner.send("#{@association.foreign_key}=", id)
@@ -3,13 +3,13 @@ module MongoMapper
3
3
  class ManyDocumentsAsProxy < ManyDocumentsProxy
4
4
  protected
5
5
  def scoped_conditions
6
- {as_type_name => @owner.class.name, as_id_name => @owner.id}
6
+ {as_type_name => @owner.class.name, as_id_name => @owner._id}
7
7
  end
8
8
 
9
9
  def apply_scope(doc)
10
10
  ensure_owner_saved
11
11
  doc.send("#{as_type_name}=", @owner.class.name)
12
- doc.send("#{as_id_name}=", @owner.id)
12
+ doc.send("#{as_id_name}=", @owner._id)
13
13
  doc
14
14
  end
15
15
 
@@ -98,7 +98,7 @@ module MongoMapper
98
98
 
99
99
  protected
100
100
  def scoped_conditions
101
- {self.foreign_key => @owner.id}
101
+ {self.foreign_key => @owner._id}
102
102
  end
103
103
 
104
104
  def scoped_options(options)
@@ -115,7 +115,7 @@ module MongoMapper
115
115
 
116
116
  def apply_scope(doc)
117
117
  ensure_owner_saved
118
- doc.send("#{self.foreign_key}=", @owner.id)
118
+ doc.send("#{self.foreign_key}=", @owner._id)
119
119
  doc
120
120
  end
121
121
 
@@ -13,9 +13,10 @@ module MongoMapper
13
13
  doc
14
14
  end
15
15
 
16
+ # TODO: test that both string and oid version work
16
17
  def find(id)
17
18
  load_target
18
- @target.detect { |item| item.id == id }
19
+ @target.detect { |item| item.id == id || item._id == id }
19
20
  end
20
21
 
21
22
  def <<(*docs)
@@ -344,15 +344,6 @@ module MongoMapper
344
344
  instances.size == 1 ? instances[0] : instances
345
345
  end
346
346
 
347
- def initialize_doc(doc)
348
- begin
349
- klass = doc['_type'].present? ? doc['_type'].constantize : self
350
- klass.new(doc)
351
- rescue NameError
352
- new(doc)
353
- end
354
- end
355
-
356
347
  def find_every(options)
357
348
  criteria, options = to_finder_options(options)
358
349
  collection.find(criteria, options).to_a.map do |doc|
@@ -442,12 +433,12 @@ module MongoMapper
442
433
 
443
434
  def destroy
444
435
  return false if frozen?
445
- self.class.delete(id) unless new?
436
+ self.class.delete(_id) unless new?
446
437
  freeze
447
438
  end
448
439
 
449
440
  def reload
450
- self.class.find(id)
441
+ self.class.find(_id)
451
442
  end
452
443
 
453
444
  private
@@ -463,7 +454,7 @@ module MongoMapper
463
454
 
464
455
  def assign_id
465
456
  if read_attribute(:_id).blank?
466
- write_attribute(:_id, Mongo::ObjectID.new.to_s)
457
+ write_attribute :_id, Mongo::ObjectID.new
467
458
  end
468
459
  end
469
460
 
@@ -16,7 +16,7 @@ module MongoMapper
16
16
 
17
17
  extend Validations::Macros
18
18
 
19
- key :_id, String
19
+ key :_id, ObjectId
20
20
  attr_accessor :_root_document
21
21
  end
22
22
  end
@@ -25,7 +25,7 @@ module MongoMapper
25
25
  def logger
26
26
  MongoMapper.logger
27
27
  end
28
-
28
+
29
29
  def inherited(subclass)
30
30
  unless subclass.embeddable?
31
31
  subclass.set_collection_name(collection_name)
@@ -48,19 +48,23 @@ module MongoMapper
48
48
 
49
49
  def key(*args)
50
50
  key = Key.new(*args)
51
+ keys[key.name] = key
51
52
 
52
- if keys[key.name].blank?
53
- keys[key.name] = key
53
+ create_accessors_for(key)
54
+ create_key_in_subclasses(*args)
55
+ create_validations_for(key)
54
56
 
55
- create_accessors_for(key)
56
- create_key_in_subclasses(*args)
57
- create_validations_for(key)
58
-
59
- key
60
- end
61
-
62
57
  key
63
58
  end
59
+
60
+ def using_object_id?
61
+ object_id_key?(:_id)
62
+ end
63
+
64
+ def object_id_key?(name)
65
+ key = keys[name.to_s]
66
+ key && key.type == ObjectId
67
+ end
64
68
 
65
69
  def embeddable?
66
70
  !self.ancestors.include?(Document)
@@ -83,11 +87,20 @@ module MongoMapper
83
87
  if instance_or_hash.is_a?(self)
84
88
  instance_or_hash
85
89
  else
86
- new(instance_or_hash)
90
+ initialize_doc(instance_or_hash)
87
91
  end
88
92
  end
89
93
 
90
94
  private
95
+ def initialize_doc(doc)
96
+ begin
97
+ klass = doc['_type'].present? ? doc['_type'].constantize : self
98
+ klass.new(doc)
99
+ rescue NameError
100
+ new(doc)
101
+ end
102
+ end
103
+
91
104
  def accessors_module
92
105
  module_defined = if method(:const_defined?).arity == 1 # Ruby 1.9 compat check
93
106
  const_defined?('MongoMapperKeys')
@@ -191,16 +204,16 @@ module MongoMapper
191
204
  end
192
205
  end
193
206
 
194
- if self.class.embeddable?
207
+ if self.class.embeddable?
195
208
  if read_attribute(:_id).blank?
196
- write_attribute :_id, Mongo::ObjectID.new.to_s
209
+ write_attribute :_id, Mongo::ObjectID.new
197
210
  @new_document = true
198
211
  else
199
212
  @new_document = false
200
213
  end
201
214
  end
202
215
  end
203
-
216
+
204
217
  def new?
205
218
  !!@new_document
206
219
  end
@@ -275,15 +288,20 @@ module MongoMapper
275
288
  end
276
289
 
277
290
  def ==(other)
278
- other.is_a?(self.class) && id == other.id
291
+ other.is_a?(self.class) && _id == other._id
279
292
  end
280
293
 
281
294
  def id
282
- read_attribute(:_id)
295
+ read_attribute(:_id).to_s
283
296
  end
284
297
 
285
298
  def id=(value)
286
- @using_custom_id = true
299
+ if self.class.using_object_id?
300
+ value = MongoMapper.normalize_object_id(value)
301
+ else
302
+ @using_custom_id = true
303
+ end
304
+
287
305
  write_attribute :_id, value
288
306
  end
289
307
 
@@ -353,7 +371,7 @@ module MongoMapper
353
371
  def write_attribute(name, value)
354
372
  key = _keys[name]
355
373
  instance_variable_set "@#{name}_before_typecast", value
356
- instance_variable_set "@#{name}", key.set(value)
374
+ instance_variable_set "@#{name}", key.set(value)
357
375
  end
358
376
 
359
377
  def embedded_associations
@@ -8,17 +8,7 @@ module MongoMapper
8
8
  # useful for understanding how MongoMapper handles the parsing of finder
9
9
  # conditions and options.
10
10
  #
11
- # @private
12
- class FinderOperator
13
- def initialize(field, operator)
14
- @field, @operator = field, operator
15
- end
16
-
17
- def to_criteria(value)
18
- {@field => {@operator => value}}
19
- end
20
- end
21
-
11
+ # @private
22
12
  class FinderOptions
23
13
  OptionKeys = [:fields, :select, :skip, :offset, :limit, :sort, :order]
24
14
 
@@ -72,10 +62,16 @@ module MongoMapper
72
62
 
73
63
  conditions.each_pair do |field, value|
74
64
  field = normalized_field(field)
65
+
66
+ if @model.object_id_key?(field) && value.is_a?(String)
67
+ value = Mongo::ObjectID.from_string(value)
68
+ end
69
+
75
70
  if field.is_a?(FinderOperator)
76
71
  criteria.merge!(field.to_criteria(value))
77
72
  next
78
73
  end
74
+
79
75
  case value
80
76
  when Array
81
77
  operator_present = field.to_s =~ /^\$/
@@ -128,4 +124,14 @@ module MongoMapper
128
124
  [field, direction]
129
125
  end
130
126
  end
127
+
128
+ class FinderOperator
129
+ def initialize(field, operator)
130
+ @field, @operator = field, operator
131
+ end
132
+
133
+ def to_criteria(value)
134
+ {@field => {@operator => value}}
135
+ end
136
+ end
131
137
  end
@@ -4,6 +4,10 @@ module MongoMapper
4
4
  def self.included(model)
5
5
  model.class_eval do
6
6
  alias_method :new_record?, :new?
7
+
8
+ def human_name
9
+ self.name.demodulize.titleize
10
+ end
7
11
  end
8
12
  end
9
13
  end
@@ -17,6 +17,10 @@ module MongoMapper
17
17
  def column_names
18
18
  keys.keys
19
19
  end
20
+
21
+ def human_name
22
+ self.name.demodulize.titleize
23
+ end
20
24
  end
21
25
  end
22
26
  end