mongo_mapper 0.12.0 → 0.13.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +35 -13
  3. data/bin/mmconsole +1 -1
  4. data/lib/mongo_mapper.rb +4 -0
  5. data/lib/mongo_mapper/connection.rb +17 -6
  6. data/lib/mongo_mapper/document.rb +1 -0
  7. data/lib/mongo_mapper/exceptions.rb +4 -1
  8. data/lib/mongo_mapper/extensions/binary.rb +1 -1
  9. data/lib/mongo_mapper/extensions/boolean.rb +20 -23
  10. data/lib/mongo_mapper/extensions/date.rb +3 -3
  11. data/lib/mongo_mapper/extensions/integer.rb +5 -1
  12. data/lib/mongo_mapper/extensions/kernel.rb +2 -0
  13. data/lib/mongo_mapper/extensions/ordered_hash.rb +23 -0
  14. data/lib/mongo_mapper/extensions/string.rb +2 -2
  15. data/lib/mongo_mapper/extensions/time.rb +7 -5
  16. data/lib/mongo_mapper/middleware/identity_map.rb +3 -4
  17. data/lib/mongo_mapper/plugins.rb +1 -1
  18. data/lib/mongo_mapper/plugins/associations.rb +11 -5
  19. data/lib/mongo_mapper/plugins/associations/base.rb +5 -3
  20. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +0 -0
  21. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +8 -8
  22. data/lib/mongo_mapper/plugins/associations/collection.rb +2 -0
  23. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +32 -7
  24. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +2 -2
  25. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +12 -12
  26. data/lib/mongo_mapper/plugins/associations/proxy.rb +5 -1
  27. data/lib/mongo_mapper/plugins/associations/single_association.rb +6 -6
  28. data/lib/mongo_mapper/plugins/clone.rb +4 -2
  29. data/lib/mongo_mapper/plugins/dirty.rb +22 -21
  30. data/lib/mongo_mapper/plugins/document.rb +4 -4
  31. data/lib/mongo_mapper/plugins/dumpable.rb +22 -0
  32. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +58 -9
  33. data/lib/mongo_mapper/plugins/identity_map.rb +42 -32
  34. data/lib/mongo_mapper/plugins/keys.rb +133 -54
  35. data/lib/mongo_mapper/plugins/keys/key.rb +68 -22
  36. data/lib/mongo_mapper/plugins/modifiers.rb +26 -19
  37. data/lib/mongo_mapper/plugins/persistence.rb +15 -5
  38. data/lib/mongo_mapper/plugins/querying.rb +15 -40
  39. data/lib/mongo_mapper/plugins/querying/{decorator.rb → decorated_plucky_query.rb} +24 -4
  40. data/lib/mongo_mapper/plugins/rails.rb +22 -2
  41. data/lib/mongo_mapper/plugins/safe.rb +8 -5
  42. data/lib/mongo_mapper/plugins/sci.rb +26 -4
  43. data/lib/mongo_mapper/plugins/scopes.rb +5 -4
  44. data/lib/mongo_mapper/plugins/timestamps.rb +11 -4
  45. data/lib/mongo_mapper/plugins/validations.rb +1 -1
  46. data/lib/mongo_mapper/utils.rb +12 -0
  47. data/lib/mongo_mapper/version.rb +1 -1
  48. data/lib/rails/generators/mongo_mapper/config/config_generator.rb +20 -7
  49. data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +6 -0
  50. data/lib/rails/generators/mongo_mapper/model/model_generator.rb +18 -1
  51. data/lib/rails/generators/mongo_mapper/model/templates/model.rb +9 -5
  52. data/{test/functional/test_accessible.rb → spec/functional/accessible_spec.rb} +29 -29
  53. data/{test/functional/associations/test_belongs_to_polymorphic_proxy.rb → spec/functional/associations/belongs_to_polymorphic_proxy_spec.rb} +10 -10
  54. data/{test/functional/associations/test_belongs_to_proxy.rb → spec/functional/associations/belongs_to_proxy_spec.rb} +82 -64
  55. data/{test/functional/associations/test_in_array_proxy.rb → spec/functional/associations/in_array_proxy_spec.rb} +68 -68
  56. data/{test/functional/associations/test_many_documents_as_proxy.rb → spec/functional/associations/many_documents_as_proxy_spec.rb} +37 -38
  57. data/{test/functional/associations/test_many_documents_proxy.rb → spec/functional/associations/many_documents_proxy_spec.rb} +233 -146
  58. data/{test/functional/associations/test_many_embedded_polymorphic_proxy.rb → spec/functional/associations/many_embedded_polymorphic_proxy_spec.rb} +19 -20
  59. data/{test/functional/associations/test_many_embedded_proxy.rb → spec/functional/associations/many_embedded_proxy_spec.rb} +23 -24
  60. data/{test/functional/associations/test_many_polymorphic_proxy.rb → spec/functional/associations/many_polymorphic_proxy_spec.rb} +45 -46
  61. data/{test/functional/associations/test_one_as_proxy.rb → spec/functional/associations/one_as_proxy_spec.rb} +75 -77
  62. data/{test/functional/associations/test_one_embedded_polymorphic_proxy.rb → spec/functional/associations/one_embedded_polymorphic_proxy_spec.rb} +31 -32
  63. data/{test/functional/associations/test_one_embedded_proxy.rb → spec/functional/associations/one_embedded_proxy_spec.rb} +10 -10
  64. data/{test/functional/associations/test_one_proxy.rb → spec/functional/associations/one_proxy_spec.rb} +125 -102
  65. data/spec/functional/associations_spec.rb +48 -0
  66. data/{test/functional/test_binary.rb → spec/functional/binary_spec.rb} +6 -6
  67. data/spec/functional/caching_spec.rb +75 -0
  68. data/{test/functional/test_callbacks.rb → spec/functional/callbacks_spec.rb} +84 -26
  69. data/{test/functional/test_dirty.rb → spec/functional/dirty_spec.rb} +57 -42
  70. data/{test/functional/test_document.rb → spec/functional/document_spec.rb} +52 -52
  71. data/spec/functional/dumpable_spec.rb +24 -0
  72. data/{test/functional/test_dynamic_querying.rb → spec/functional/dynamic_querying_spec.rb} +14 -14
  73. data/{test/functional/test_embedded_document.rb → spec/functional/embedded_document_spec.rb} +51 -42
  74. data/{test/functional/test_equality.rb → spec/functional/equality_spec.rb} +4 -4
  75. data/spec/functional/extensions_spec.rb +16 -0
  76. data/{test/functional/test_identity_map.rb → spec/functional/identity_map_spec.rb} +73 -61
  77. data/spec/functional/indexes_spec.rb +48 -0
  78. data/spec/functional/keys_spec.rb +224 -0
  79. data/{test/functional/test_logger.rb → spec/functional/logger_spec.rb} +6 -6
  80. data/spec/functional/modifiers_spec.rb +550 -0
  81. data/spec/functional/pagination_spec.rb +89 -0
  82. data/spec/functional/protected_spec.rb +199 -0
  83. data/spec/functional/querying_spec.rb +1003 -0
  84. data/spec/functional/rails_spec.rb +55 -0
  85. data/spec/functional/safe_spec.rb +163 -0
  86. data/{test/functional/test_sci.rb → spec/functional/sci_spec.rb} +123 -34
  87. data/{test/functional/test_scopes.rb → spec/functional/scopes_spec.rb} +59 -26
  88. data/spec/functional/timestamps_spec.rb +97 -0
  89. data/{test/functional/test_touch.rb → spec/functional/touch_spec.rb} +13 -13
  90. data/spec/functional/userstamps_spec.rb +46 -0
  91. data/{test/functional/test_validations.rb → spec/functional/validations_spec.rb} +64 -64
  92. data/spec/spec_helper.rb +81 -0
  93. data/spec/support/matchers.rb +24 -0
  94. data/{test → spec/support}/models.rb +1 -6
  95. data/spec/unit/associations/base_spec.rb +146 -0
  96. data/spec/unit/associations/belongs_to_association_spec.rb +30 -0
  97. data/spec/unit/associations/many_association_spec.rb +64 -0
  98. data/spec/unit/associations/one_association_spec.rb +48 -0
  99. data/{test/unit/associations/test_proxy.rb → spec/unit/associations/proxy_spec.rb} +21 -21
  100. data/{test/unit/test_clone.rb → spec/unit/clone_spec.rb} +21 -11
  101. data/spec/unit/config_generator_spec.rb +24 -0
  102. data/{test/unit/test_document.rb → spec/unit/document_spec.rb} +42 -42
  103. data/{test/unit/test_dynamic_finder.rb → spec/unit/dynamic_finder_spec.rb} +28 -28
  104. data/{test/unit/test_embedded_document.rb → spec/unit/embedded_document_spec.rb} +102 -108
  105. data/{test/unit/test_equality.rb → spec/unit/equality_spec.rb} +7 -7
  106. data/{test/unit/test_exceptions.rb → spec/unit/exceptions_spec.rb} +3 -3
  107. data/{test/unit/test_extensions.rb → spec/unit/extensions_spec.rb} +85 -71
  108. data/spec/unit/identity_map_middleware_spec.rb +134 -0
  109. data/{test/unit/test_inspect.rb → spec/unit/inspect_spec.rb} +8 -8
  110. data/{test/unit/test_key.rb → spec/unit/key_spec.rb} +82 -52
  111. data/spec/unit/keys_spec.rb +155 -0
  112. data/spec/unit/model_generator_spec.rb +47 -0
  113. data/spec/unit/mongo_mapper_spec.rb +184 -0
  114. data/spec/unit/pagination_spec.rb +11 -0
  115. data/{test/unit/test_plugins.rb → spec/unit/plugins_spec.rb} +14 -14
  116. data/spec/unit/rails_compatibility_spec.rb +40 -0
  117. data/{test/unit/test_rails_reflect_on_association.rb → spec/unit/rails_reflect_on_association_spec.rb} +9 -9
  118. data/{test/unit/test_rails.rb → spec/unit/rails_spec.rb} +31 -31
  119. data/spec/unit/serialization_spec.rb +169 -0
  120. data/spec/unit/serializers/json_serializer_spec.rb +218 -0
  121. data/spec/unit/serializers/xml_serializer_spec.rb +198 -0
  122. data/{test/unit/test_time_zones.rb → spec/unit/time_zones_spec.rb} +8 -8
  123. data/{test/unit/test_translation.rb → spec/unit/translation_spec.rb} +6 -6
  124. data/{test/unit/test_validations.rb → spec/unit/validations_spec.rb} +72 -59
  125. metadata +199 -179
  126. data/test/_NOTE_ON_TESTING +0 -1
  127. data/test/functional/test_associations.rb +0 -46
  128. data/test/functional/test_caching.rb +0 -77
  129. data/test/functional/test_indexes.rb +0 -50
  130. data/test/functional/test_modifiers.rb +0 -537
  131. data/test/functional/test_pagination.rb +0 -91
  132. data/test/functional/test_protected.rb +0 -201
  133. data/test/functional/test_querying.rb +0 -935
  134. data/test/functional/test_safe.rb +0 -76
  135. data/test/functional/test_timestamps.rb +0 -62
  136. data/test/functional/test_userstamps.rb +0 -44
  137. data/test/support/railtie.rb +0 -4
  138. data/test/support/railtie/autoloaded.rb +0 -2
  139. data/test/support/railtie/not_autoloaded.rb +0 -3
  140. data/test/support/railtie/parent.rb +0 -3
  141. data/test/test_active_model_lint.rb +0 -18
  142. data/test/test_helper.rb +0 -93
  143. data/test/unit/associations/test_base.rb +0 -146
  144. data/test/unit/associations/test_belongs_to_association.rb +0 -29
  145. data/test/unit/associations/test_many_association.rb +0 -63
  146. data/test/unit/associations/test_one_association.rb +0 -47
  147. data/test/unit/serializers/test_json_serializer.rb +0 -216
  148. data/test/unit/serializers/test_xml_serializer.rb +0 -196
  149. data/test/unit/test_identity_map_middleware.rb +0 -132
  150. data/test/unit/test_keys.rb +0 -65
  151. data/test/unit/test_mongo_mapper.rb +0 -157
  152. data/test/unit/test_pagination.rb +0 -11
  153. data/test/unit/test_rails_compatibility.rb +0 -38
  154. data/test/unit/test_serialization.rb +0 -166
@@ -71,64 +71,71 @@ module MongoMapper
71
71
  collection.update(criteria, {modifier => updates}, options.merge(:multi => true))
72
72
  else
73
73
  collection.update(criteria, {modifier => updates}, :multi => true)
74
- end
74
+ end
75
75
  end
76
76
 
77
77
  def criteria_and_keys_from_args(args)
78
78
  if args[0].is_a?(Hash)
79
79
  criteria = args[0]
80
- updates = args[1]
81
- options = args[2]
80
+ updates = args[1]
81
+ options = args[2]
82
82
  else
83
- split_args = args.partition{|a| a.is_a?(BSON::ObjectId)}
84
- criteria = {:id => split_args[0]}
85
- updates = split_args[1].first
86
- options = split_args[1].last
87
- end
83
+ criteria, (updates, options) = args.partition { |a| !a.is_a?(Hash) }
84
+ criteria = { :id => criteria }
85
+ end
86
+ upgrade_legacy_safe_usage!(options)
87
+
88
88
  [criteria_hash(criteria).to_hash, updates, options]
89
89
  end
90
+
91
+ def upgrade_legacy_safe_usage!(options)
92
+ if options and options.key?(:safe)
93
+ options.merge! Utils.get_safe_options(options)
94
+ options.delete :safe
95
+ end
96
+ end
90
97
  end
91
98
 
92
99
  def unset(*args)
93
- self.class.unset(id, *args)
100
+ self.class.unset({:_id => id}, *args)
94
101
  end
95
102
 
96
103
  def increment(hash, options=nil)
97
- self.class.increment(id, hash, options)
104
+ self.class.increment({:_id => id}, hash, options)
98
105
  end
99
106
 
100
107
  def decrement(hash, options=nil)
101
- self.class.decrement(id, hash, options)
108
+ self.class.decrement({:_id => id}, hash, options)
102
109
  end
103
110
 
104
111
  def set(hash, options=nil)
105
- self.class.set(id, hash, options)
112
+ self.class.set({:_id => id}, hash, options)
106
113
  end
107
114
 
108
115
  def push(hash, options=nil)
109
- self.class.push(id, hash, options)
116
+ self.class.push({:_id => id}, hash, options)
110
117
  end
111
118
 
112
119
  def push_all(hash, options=nil)
113
- self.class.push_all(id, hash, options)
120
+ self.class.push_all({:_id => id}, hash, options)
114
121
  end
115
122
 
116
123
  def pull(hash, options=nil)
117
- self.class.pull(id, hash, options)
124
+ self.class.pull({:_id => id}, hash, options)
118
125
  end
119
126
 
120
127
  def pull_all(hash, options=nil)
121
- self.class.pull_all(id, hash, options)
128
+ self.class.pull_all({:_id => id}, hash, options)
122
129
  end
123
130
 
124
131
  def add_to_set(hash, options=nil)
125
- self.class.push_uniq(id, hash, options)
132
+ self.class.push_uniq({:_id => id}, hash, options)
126
133
  end
127
134
  alias push_uniq add_to_set
128
135
 
129
136
  def pop(hash, options=nil)
130
- self.class.pop(id, hash, options)
137
+ self.class.pop({:_id => id}, hash, options)
131
138
  end
132
139
  end
133
140
  end
134
- end
141
+ end
@@ -5,9 +5,18 @@ module MongoMapper
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
+ def inherited(subclass)
9
+ unless subclass.embeddable?
10
+ subclass.connection(connection)
11
+ subclass.set_database_name(database_name)
12
+ subclass.set_collection_name(collection_name) unless subclass.explicit_collection_defined?
13
+ end
14
+ super
15
+ end
16
+
8
17
  def connection(mongo_connection=nil)
9
18
  assert_supported
10
- if mongo_connection.nil?
19
+ if mongo_connection.nil? && MongoMapper.connection?
11
20
  @connection ||= MongoMapper.connection
12
21
  else
13
22
  @connection = mongo_connection
@@ -22,7 +31,7 @@ module MongoMapper
22
31
 
23
32
  def database_name
24
33
  assert_supported
25
- @database_name
34
+ @database_name ||= nil # ||= idiom prevents uninitialized ivar warnings.
26
35
  end
27
36
 
28
37
  def database
@@ -51,8 +60,9 @@ module MongoMapper
51
60
 
52
61
  private
53
62
  def assert_supported
54
- if embeddable?
55
- raise NotSupported.new('This is not supported for embeddable documents at this time.')
63
+ @embeddable ||= embeddable?
64
+ if @embeddable
65
+ raise MongoMapper::NotSupported.new('This is not supported for embeddable documents at this time.')
56
66
  end
57
67
  end
58
68
  end
@@ -66,4 +76,4 @@ module MongoMapper
66
76
  end
67
77
  end
68
78
  end
69
- end
79
+ end
@@ -1,5 +1,5 @@
1
1
  # encoding: UTF-8
2
- require 'mongo_mapper/plugins/querying/decorator'
2
+ require 'mongo_mapper/plugins/querying/decorated_plucky_query'
3
3
 
4
4
  module MongoMapper
5
5
  module Plugins
@@ -24,11 +24,17 @@ module MongoMapper
24
24
  end
25
25
 
26
26
  def create(*docs)
27
- initialize_each(*docs) { |doc| doc.save }
27
+ initialize_each(*docs) do |doc|
28
+ yield doc if block_given?
29
+ doc.save
30
+ end
28
31
  end
29
32
 
30
33
  def create!(*docs)
31
- initialize_each(*docs) { |doc| doc.save! }
34
+ initialize_each(*docs) do |doc|
35
+ yield doc if block_given?
36
+ doc.save!
37
+ end
32
38
  end
33
39
 
34
40
  def update(*args)
@@ -40,31 +46,15 @@ module MongoMapper
40
46
  end
41
47
  end
42
48
 
43
- def delete(*ids)
44
- query(:_id => ids.flatten).remove
45
- end
46
-
47
- def delete_all(options={})
48
- query(options).remove
49
- end
50
-
51
- def destroy(*ids)
52
- find_some!(ids.flatten).each { |doc| doc.destroy }
53
- end
54
-
55
- def destroy_all(options={})
56
- find_each(options) { |document| document.destroy }
57
- end
58
-
59
49
  # @api private for now
60
50
  def query(options={})
61
- query = Plucky::Query.new(collection, :transformer => transformer)
62
- query.extend(Decorator)
51
+ query = MongoMapper::Plugins::Querying::DecoratedPluckyQuery.new(collection, :transformer => transformer)
63
52
  query.object_ids(object_id_keys)
64
53
  query.amend(options)
65
54
  query.model(self)
66
55
  query
67
56
  end
57
+ alias_method :scoped, :query
68
58
 
69
59
  # @api private for now
70
60
  def criteria_hash(criteria={})
@@ -76,22 +66,6 @@ module MongoMapper
76
66
  @transformer ||= lambda { |doc| load(doc) }
77
67
  end
78
68
 
79
- def find_some(ids, options={})
80
- query = query(options).amend(:_id => ids.flatten.compact.uniq)
81
- query.all
82
- end
83
-
84
- def find_some!(ids, options={})
85
- ids = ids.flatten.compact.uniq
86
- docs = find_some(ids, options)
87
-
88
- if ids.size != docs.size
89
- raise DocumentNotFound, "Couldn't find all of the ids (#{ids.to_sentence}). Found #{docs.size}, but was expecting #{ids.size}"
90
- end
91
-
92
- docs
93
- end
94
-
95
69
  def initialize_each(*docs)
96
70
  instances = []
97
71
  docs = [{}] if docs.blank?
@@ -149,16 +123,17 @@ module MongoMapper
149
123
  end
150
124
 
151
125
  def create(options={})
152
- save_to_collection(options)
126
+ save_to_collection(options.merge(:persistence_method => :insert))
153
127
  end
154
128
 
155
129
  def update(options={})
156
- save_to_collection(options)
130
+ save_to_collection(options.merge(:persistence_method => :save))
157
131
  end
158
132
 
159
133
  def save_to_collection(options={})
160
134
  @_new = false
161
- collection.save(to_mongo, :safe => options[:safe])
135
+ method = options.delete(:persistence_method) || :save
136
+ collection.send(method, to_mongo, Utils.get_safe_options(options))
162
137
  end
163
138
  end
164
139
  end
@@ -2,11 +2,27 @@
2
2
  module MongoMapper
3
3
  module Plugins
4
4
  module Querying
5
- Methods = Plucky::Methods + [:find!]
5
+ Methods = Plucky::Methods + [:delete, :delete_all, :destroy, :destroy_all, :find!]
6
6
 
7
- module Decorator
7
+ class DecoratedPluckyQuery < ::Plucky::Query
8
8
  include DynamicQuerying::ClassMethods
9
9
 
10
+ def delete(*ids)
11
+ where(:_id => ids.flatten).remove
12
+ end
13
+
14
+ def delete_all(options = {})
15
+ where(options).remove
16
+ end
17
+
18
+ def destroy(*ids)
19
+ [find!(*ids.flatten.compact.uniq)].flatten.each { |doc| doc.destroy }
20
+ end
21
+
22
+ def destroy_all(options={})
23
+ find_each(options) { |document| document.destroy }
24
+ end
25
+
10
26
  def model(model=nil)
11
27
  return @model if model.nil?
12
28
  @model = model
@@ -14,6 +30,7 @@ module MongoMapper
14
30
  end
15
31
 
16
32
  def find!(*ids)
33
+ ids = Array(ids).flatten.uniq
17
34
  raise DocumentNotFound, "Couldn't find without an ID" if ids.size == 0
18
35
 
19
36
  find(*ids).tap do |result|
@@ -27,8 +44,11 @@ module MongoMapper
27
44
  def method_missing(method, *args, &block)
28
45
  return super unless model.respond_to?(method)
29
46
  result = model.send(method, *args, &block)
30
- return super unless result.is_a?(Plucky::Query)
31
- merge(result)
47
+ if result.is_a?(Plucky::Query)
48
+ merge(result)
49
+ else
50
+ result
51
+ end
32
52
  end
33
53
  end
34
54
  end
@@ -26,13 +26,25 @@ module MongoMapper
26
26
  end
27
27
 
28
28
  def read_attribute_before_type_cast(name)
29
- read_key_before_type_cast(name)
29
+ @__mm_pre_cast ||= {}
30
+ name = unalias_key name
31
+ if !@__mm_pre_cast.key?(name)
32
+ @__mm_pre_cast[name] = read_attribute(name)
33
+ end
34
+ @__mm_pre_cast[name]
30
35
  end
31
36
 
32
37
  def write_attribute(name, value)
33
38
  self[name] = value
34
39
  end
35
40
 
41
+ def write_key(name, value)
42
+ name = unalias_key name
43
+ @__mm_pre_cast ||= {}
44
+ @__mm_pre_cast[name.to_s] = value
45
+ super
46
+ end
47
+
36
48
  module ClassMethods
37
49
  def has_one(*args)
38
50
  one(*args)
@@ -43,7 +55,7 @@ module MongoMapper
43
55
  end
44
56
 
45
57
  def column_names
46
- keys.keys
58
+ unaliased_keys.keys
47
59
  end
48
60
 
49
61
  # Returns returns an ActiveRecordAssociationAdapter for an association. This adapter has an API that is a
@@ -52,6 +64,14 @@ module MongoMapper
52
64
  def reflect_on_association(name)
53
65
  ActiveRecordAssociationAdapter.for_association(associations[name]) if associations[name]
54
66
  end
67
+
68
+ def create_accessors_for(key)
69
+ super do
70
+ define_method "#{key.name}_before_type_cast" do
71
+ read_attribute_before_type_cast key.name
72
+ end
73
+ end
74
+ end
55
75
  end
56
76
  end
57
77
  end
@@ -5,22 +5,25 @@ module MongoMapper
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
+ attr_reader :safe_options
9
+
8
10
  def inherited(subclass)
9
11
  super
10
- subclass.safe if safe?
12
+ subclass.safe(safe_options) if safe?
11
13
  end
12
14
 
13
- def safe
14
- @safe = true
15
+ def safe(options = true)
16
+ @safe_options = options
15
17
  end
16
18
 
17
19
  def safe?
18
- @safe == true
20
+ @safe_options ||= nil
21
+ !!@safe_options
19
22
  end
20
23
  end
21
24
 
22
25
  def save_to_collection(options={})
23
- options[:safe] = self.class.safe? unless options.key?(:safe)
26
+ options[:safe] = self.class.safe_options if !options.key?(:safe) && self.class.safe?
24
27
  super
25
28
  end
26
29
  end
@@ -11,10 +11,11 @@ module MongoMapper
11
11
  module ClassMethods
12
12
  def inherited(subclass)
13
13
  key :_type, String unless key?(:_type)
14
- subclass.instance_variable_set("@single_collection_inherited", true)
15
- subclass.set_collection_name(collection_name) unless subclass.embeddable?
16
- subclass.single_collection_parent = self
17
14
  super
15
+ if @collection_name == subclass.instance_variable_get("@collection_name")
16
+ subclass.single_collection_parent = self
17
+ subclass.instance_variable_set("@single_collection_inherited", true)
18
+ end
18
19
  end
19
20
 
20
21
  def single_collection_root
@@ -29,6 +30,27 @@ module MongoMapper
29
30
  root
30
31
  end
31
32
 
33
+ def criteria_hash(criteria={})
34
+ if single_collection_inherited?
35
+ super criteria.merge(:_type => name)
36
+ else
37
+ super
38
+ end
39
+ end
40
+
41
+ def set_collection_name(name)
42
+ if single_collection_inherited?
43
+ single_collection_parent = nil
44
+ @single_collection_inherited = false
45
+ end
46
+ @collection_defined = true
47
+ super
48
+ end
49
+
50
+ def explicit_collection_defined?
51
+ @collection_defined == true
52
+ end
53
+
32
54
  def single_collection_parent
33
55
  @single_collection_parent
34
56
  end
@@ -38,7 +60,7 @@ module MongoMapper
38
60
  end
39
61
 
40
62
  def single_collection_inherited?
41
- @single_collection_inherited == true
63
+ !!(@single_collection_inherited ||= false)
42
64
  end
43
65
 
44
66
  def query(options={})
@@ -10,18 +10,19 @@ module MongoMapper
10
10
 
11
11
  module ClassMethods
12
12
  def scope(name, scope_options={})
13
- scopes[name] = lambda do |*args|
13
+ # Assign to _scopes instead of using []= to avoid mixing subclass scopes
14
+ self._scopes = scopes.merge(name => lambda do |*args|
14
15
  result = scope_options.is_a?(Proc) ? scope_options.call(*args) : scope_options
15
16
  result = self.query(result) if result.is_a?(Hash)
16
17
  self.query.merge(result)
17
- end
18
+ end)
18
19
  singleton_class.send :define_method, name, &scopes[name]
19
20
  end
20
21
 
21
22
  def scopes
22
- self._scopes || self._scopes = {}
23
+ self._scopes ||= {}
23
24
  end
24
25
  end
25
26
  end
26
27
  end
27
- end
28
+ end