mongo_mapper 0.9.2 → 0.10.0
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/UPGRADES +6 -0
- data/lib/mongo_mapper.rb +1 -2
- data/lib/mongo_mapper/document.rb +0 -1
- data/lib/mongo_mapper/embedded_document.rb +0 -1
- data/lib/mongo_mapper/extensions/float.rb +1 -1
- data/lib/mongo_mapper/plugins.rb +2 -8
- data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +2 -0
- data/lib/mongo_mapper/plugins/associations/many_association.rb +4 -4
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +9 -1
- data/lib/mongo_mapper/plugins/associations/one_as_proxy.rb +22 -0
- data/lib/mongo_mapper/plugins/associations/one_association.rb +29 -1
- data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +0 -1
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +43 -16
- data/lib/mongo_mapper/plugins/clone.rb +1 -1
- data/lib/mongo_mapper/plugins/dirty.rb +6 -15
- data/lib/mongo_mapper/plugins/document.rb +5 -5
- data/lib/mongo_mapper/plugins/embedded_callbacks.rb +3 -3
- data/lib/mongo_mapper/plugins/keys.rb +0 -19
- data/lib/mongo_mapper/plugins/keys/key.rb +0 -4
- data/lib/mongo_mapper/railtie.rb +1 -2
- data/lib/mongo_mapper/version.rb +1 -1
- data/test/functional/associations/test_belongs_to_proxy.rb +15 -0
- data/test/functional/associations/test_many_documents_proxy.rb +161 -0
- data/test/functional/associations/test_one_as_proxy.rb +485 -0
- data/test/functional/associations/test_one_proxy.rb +188 -27
- data/test/functional/test_dirty.rb +9 -0
- data/test/functional/test_document.rb +5 -0
- data/test/support/railtie.rb +4 -0
- data/test/support/railtie/autoloaded.rb +2 -0
- data/test/support/railtie/not_autoloaded.rb +3 -0
- data/test/support/railtie/parent.rb +3 -0
- data/test/unit/associations/test_one_association.rb +18 -0
- data/test/unit/test_extensions.rb +4 -0
- data/test/unit/test_keys.rb +0 -22
- data/test/unit/test_plugins.rb +1 -46
- data/test/unit/test_railtie.rb +61 -0
- metadata +18 -14
- data/lib/mongo_mapper/support/descendant_appends.rb +0 -45
- data/test/functional/test_string_id_compatibility.rb +0 -75
- data/test/unit/test_descendant_appends.rb +0 -63
data/UPGRADES
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
0.9 => 0.10
|
2
|
+
* Using String IDs are no longer supported. If you are declaring your own ID, ensure it is an ObjectId, and set the default
|
3
|
+
key :_id, ObjectId, :default => lambda { BSON::ObjectId.new }
|
4
|
+
* The :dependent association option now applies to both when the parent is destroyed and when the association is reassigned (one and many associations)
|
5
|
+
* The default :dependent option is now :nullify for both when the parent is destroyed and when the association is reassigned
|
6
|
+
|
1
7
|
0.8.6 => 0.9
|
2
8
|
* [attribute]_before_typecast should become [attribute]_before_type_cast (note the extra _)
|
3
9
|
* Change validates_exclusion_of :within option to :in
|
data/lib/mongo_mapper.rb
CHANGED
@@ -72,6 +72,7 @@ module MongoMapper
|
|
72
72
|
autoload :ManyEmbeddedPolymorphicProxy, 'mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy'
|
73
73
|
autoload :ManyDocumentsAsProxy, 'mongo_mapper/plugins/associations/many_documents_as_proxy'
|
74
74
|
autoload :OneProxy, 'mongo_mapper/plugins/associations/one_proxy'
|
75
|
+
autoload :OneAsProxy, 'mongo_mapper/plugins/associations/one_as_proxy'
|
75
76
|
autoload :OneEmbeddedProxy, 'mongo_mapper/plugins/associations/one_embedded_proxy'
|
76
77
|
autoload :InArrayProxy, 'mongo_mapper/plugins/associations/in_array_proxy'
|
77
78
|
end
|
@@ -84,8 +85,6 @@ Dir[File.join(File.dirname(__FILE__), 'mongo_mapper', 'extensions', '*.rb')].eac
|
|
84
85
|
require extension
|
85
86
|
end
|
86
87
|
|
87
|
-
require 'mongo_mapper/support/descendant_appends'
|
88
|
-
|
89
88
|
# FIXME: autoload with proxy is failing, need to investigate
|
90
89
|
require 'mongo_mapper/plugins/associations/proxy'
|
91
90
|
|
data/lib/mongo_mapper/plugins.rb
CHANGED
@@ -8,14 +8,8 @@ module MongoMapper
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def plugin(mod)
|
11
|
-
|
12
|
-
|
13
|
-
else
|
14
|
-
warn "[DEPRECATED] Plugins must extend ActiveSupport::Concern"
|
15
|
-
extend mod::ClassMethods if mod.const_defined?(:ClassMethods)
|
16
|
-
include mod::InstanceMethods if mod.const_defined?(:InstanceMethods)
|
17
|
-
mod.configure(self) if mod.respond_to?(:configure)
|
18
|
-
end
|
11
|
+
raise ArgumentError, "Plugins must extend ActiveSupport::Concern" unless ActiveSupport::Concern === mod
|
12
|
+
include mod
|
19
13
|
direct_descendants.each {|model| model.send(:include, mod) }
|
20
14
|
plugins << mod
|
21
15
|
end
|
@@ -41,11 +41,11 @@ module MongoMapper
|
|
41
41
|
end
|
42
42
|
end_eval
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
options = self.options
|
44
|
+
association = self
|
45
|
+
options = self.options
|
47
46
|
|
48
|
-
|
47
|
+
model.before_destroy do
|
48
|
+
if !association.embeddable?
|
49
49
|
case options[:dependent]
|
50
50
|
when :destroy
|
51
51
|
self.get_proxy(association).destroy_all
|
@@ -8,7 +8,15 @@ module MongoMapper
|
|
8
8
|
|
9
9
|
def replace(docs)
|
10
10
|
load_target
|
11
|
-
|
11
|
+
|
12
|
+
(target - docs).each do |t|
|
13
|
+
case options[:dependent]
|
14
|
+
when :destroy then t.destroy
|
15
|
+
when :delete_all then t.delete
|
16
|
+
else t.update_attributes(self.foreign_key => nil)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
12
20
|
docs.each { |doc| prepare(doc).save }
|
13
21
|
reset
|
14
22
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module MongoMapper
|
3
|
+
module Plugins
|
4
|
+
module Associations
|
5
|
+
class OneAsProxy < OneProxy
|
6
|
+
protected
|
7
|
+
def criteria
|
8
|
+
{type_key_name => proxy_owner.class.name, id_key_name => proxy_owner.id}
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def type_key_name
|
13
|
+
"#{options[:as]}_type"
|
14
|
+
end
|
15
|
+
|
16
|
+
def id_key_name
|
17
|
+
"#{options[:as]}_id"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -8,7 +8,35 @@ module MongoMapper
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def proxy_class
|
11
|
-
@proxy_class ||=
|
11
|
+
@proxy_class ||=
|
12
|
+
if klass.embeddable?
|
13
|
+
OneEmbeddedProxy
|
14
|
+
elsif as?
|
15
|
+
OneAsProxy
|
16
|
+
else
|
17
|
+
OneProxy
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup(model)
|
22
|
+
super
|
23
|
+
|
24
|
+
association = self
|
25
|
+
options = self.options
|
26
|
+
|
27
|
+
model.before_destroy do
|
28
|
+
if !association.embeddable?
|
29
|
+
proxy = self.get_proxy(association)
|
30
|
+
|
31
|
+
unless proxy.nil?
|
32
|
+
case options[:dependent]
|
33
|
+
when :destroy then proxy.destroy
|
34
|
+
when :delete then proxy.delete
|
35
|
+
else proxy.nullify
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
12
40
|
end
|
13
41
|
|
14
42
|
def autosave?
|
@@ -19,38 +19,51 @@ module MongoMapper
|
|
19
19
|
load_target
|
20
20
|
|
21
21
|
if !target.nil? && target != doc
|
22
|
-
if
|
22
|
+
if target.persisted?
|
23
23
|
case options[:dependent]
|
24
|
-
when :delete
|
25
|
-
|
26
|
-
|
27
|
-
target
|
28
|
-
when :nullify
|
29
|
-
target[foreign_key] = nil
|
24
|
+
when :delete then target.delete
|
25
|
+
when :destroy then target.destroy
|
26
|
+
else
|
27
|
+
nullify_scope(target)
|
30
28
|
target.save
|
31
29
|
end
|
32
30
|
end
|
33
31
|
end
|
34
|
-
|
35
|
-
|
36
|
-
target.update_attributes(foreign_key => nil) unless target.nil?
|
37
|
-
else
|
32
|
+
|
33
|
+
unless doc.nil?
|
38
34
|
proxy_owner.save unless proxy_owner.persisted?
|
39
35
|
doc = klass.new(doc) unless doc.is_a?(klass)
|
40
|
-
doc
|
36
|
+
apply_scope(doc)
|
41
37
|
doc.save unless doc.persisted?
|
42
|
-
loaded
|
43
|
-
@target = doc
|
44
38
|
end
|
39
|
+
|
40
|
+
loaded
|
41
|
+
@target = doc
|
42
|
+
end
|
43
|
+
|
44
|
+
def destroy
|
45
|
+
target.destroy
|
46
|
+
reset
|
47
|
+
end
|
48
|
+
|
49
|
+
def delete
|
50
|
+
target.delete
|
51
|
+
reset
|
52
|
+
end
|
53
|
+
|
54
|
+
def nullify
|
55
|
+
nullify_scope(target)
|
56
|
+
target.save
|
57
|
+
reset
|
45
58
|
end
|
46
59
|
|
47
60
|
protected
|
48
61
|
def find_target
|
49
|
-
target_class.first(association.query_options.merge(
|
62
|
+
target_class.first(association.query_options.merge(criteria))
|
50
63
|
end
|
51
64
|
|
52
65
|
def instantiate_target(instantiator, attrs={})
|
53
|
-
@target = target_class.send(instantiator, attrs.update(
|
66
|
+
@target = target_class.send(instantiator, attrs.update(criteria))
|
54
67
|
loaded
|
55
68
|
@target
|
56
69
|
end
|
@@ -62,6 +75,20 @@ module MongoMapper
|
|
62
75
|
def foreign_key
|
63
76
|
options[:foreign_key] || proxy_owner.class.name.foreign_key
|
64
77
|
end
|
78
|
+
|
79
|
+
def criteria
|
80
|
+
{self.foreign_key => proxy_owner.id}
|
81
|
+
end
|
82
|
+
|
83
|
+
def nullify_scope(doc)
|
84
|
+
criteria.each { |key, value| doc[key] = nil }
|
85
|
+
doc
|
86
|
+
end
|
87
|
+
|
88
|
+
def apply_scope(doc)
|
89
|
+
criteria.each { |key, value| doc[key] = value }
|
90
|
+
doc
|
91
|
+
end
|
65
92
|
end
|
66
93
|
end
|
67
94
|
end
|
@@ -20,10 +20,6 @@ module MongoMapper
|
|
20
20
|
clear_changes { super }
|
21
21
|
end
|
22
22
|
|
23
|
-
def save!(*)
|
24
|
-
clear_changes { super }
|
25
|
-
end
|
26
|
-
|
27
23
|
def reload(*)
|
28
24
|
super.tap { clear_changes }
|
29
25
|
end
|
@@ -51,19 +47,14 @@ module MongoMapper
|
|
51
47
|
|
52
48
|
def write_key(key, value)
|
53
49
|
key = key.to_s
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
def attribute_should_change?(key, old, value)
|
61
|
-
attribute_changed?(key) == false && attribute_value_changed?(key, old, value)
|
50
|
+
attribute_will_change!(key) unless attribute_changed?(key)
|
51
|
+
super(key, value).tap do
|
52
|
+
changed_attributes.delete(key) unless attribute_value_changed?(key)
|
53
|
+
end
|
62
54
|
end
|
63
55
|
|
64
|
-
def attribute_value_changed?(key_name
|
65
|
-
|
66
|
-
old != value
|
56
|
+
def attribute_value_changed?(key_name)
|
57
|
+
attribute_was(key_name) != read_key(key_name)
|
67
58
|
end
|
68
59
|
end
|
69
60
|
end
|
@@ -21,12 +21,12 @@ module MongoMapper
|
|
21
21
|
|
22
22
|
def reload
|
23
23
|
if doc = collection.find_one(:_id => id)
|
24
|
-
|
25
|
-
|
26
|
-
get_proxy(association).reset
|
27
|
-
end
|
28
|
-
instance.attributes = doc
|
24
|
+
self.class.associations.each_value do |association|
|
25
|
+
get_proxy(association).reset
|
29
26
|
end
|
27
|
+
instance_variables.each { |ivar| instance_variable_set(ivar, nil) }
|
28
|
+
self.attributes = doc
|
29
|
+
self
|
30
30
|
else
|
31
31
|
raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
|
32
32
|
end
|
@@ -11,7 +11,7 @@ module MongoMapper
|
|
11
11
|
end
|
12
12
|
|
13
13
|
module InstanceMethods
|
14
|
-
def run_callbacks(callback, &block)
|
14
|
+
def run_callbacks(callback, *args, &block)
|
15
15
|
embedded_docs = []
|
16
16
|
|
17
17
|
embedded_associations.each do |association|
|
@@ -20,12 +20,12 @@ module MongoMapper
|
|
20
20
|
|
21
21
|
block = embedded_docs.inject(block) do |chain, doc|
|
22
22
|
if doc.class.respond_to?("_#{callback}_callbacks")
|
23
|
-
lambda { doc.run_callbacks(callback, &chain) }
|
23
|
+
lambda { doc.run_callbacks(callback, *args, &chain) }
|
24
24
|
else
|
25
25
|
chain
|
26
26
|
end
|
27
27
|
end
|
28
|
-
super callback, &block
|
28
|
+
super callback, *args, &block
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -47,11 +47,6 @@ module MongoMapper
|
|
47
47
|
object_id_keys.include?(name.to_sym)
|
48
48
|
end
|
49
49
|
|
50
|
-
# API Private
|
51
|
-
def can_default_id?
|
52
|
-
keys['_id'].can_default_id?
|
53
|
-
end
|
54
|
-
|
55
50
|
def to_mongo(instance)
|
56
51
|
return nil if instance.nil?
|
57
52
|
instance.to_mongo
|
@@ -163,7 +158,6 @@ module MongoMapper
|
|
163
158
|
|
164
159
|
module InstanceMethods
|
165
160
|
def initialize(attrs={})
|
166
|
-
default_id_value(attrs)
|
167
161
|
@_new = true
|
168
162
|
assign(attrs)
|
169
163
|
end
|
@@ -171,7 +165,6 @@ module MongoMapper
|
|
171
165
|
def initialize_from_database(attrs={})
|
172
166
|
@_new = false
|
173
167
|
load_from_database(attrs)
|
174
|
-
default_id_value(attrs)
|
175
168
|
self
|
176
169
|
end
|
177
170
|
|
@@ -266,18 +259,6 @@ module MongoMapper
|
|
266
259
|
keys.values.select { |key| key.embeddable? }
|
267
260
|
end
|
268
261
|
|
269
|
-
def default_id_value(attrs={})
|
270
|
-
id_provided = !attrs.nil? && attrs.keys.map { |k| k.to_s }.detect { |k| k == 'id' || k == '_id' }
|
271
|
-
if !id_provided && self.class.can_default_id?
|
272
|
-
unless keys['_id'].default_value
|
273
|
-
warn "[DEPRECATED] Custom IDs will no longer be automatically populated. If you definte your own :_id key, set a default:\n key :_id, String, :default => lambda { BSON::ObjectId.new }"
|
274
|
-
warn caller.grep(/test/).join("\n")
|
275
|
-
end
|
276
|
-
|
277
|
-
write_key :_id, BSON::ObjectId.new
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
262
|
private
|
282
263
|
def load_from_database(attrs)
|
283
264
|
return if attrs.blank?
|
data/lib/mongo_mapper/railtie.rb
CHANGED
@@ -37,10 +37,9 @@ module MongoMapper
|
|
37
37
|
initializer "mongo_mapper.prepare_dispatcher" do |app|
|
38
38
|
# See http://groups.google.com/group/mongomapper/browse_thread/thread/68f62e8eda43b43a/4841dba76938290c
|
39
39
|
# to_prepare is called before each request in development mode and the first request in production.
|
40
|
+
|
40
41
|
ActionDispatch::Callbacks.to_prepare do
|
41
42
|
unless app.config.cache_classes
|
42
|
-
# Rails reloading was making descendants fill up and leak memory, these make sure they get cleared
|
43
|
-
ActiveSupport::DescendantsTracker.clear
|
44
43
|
MongoMapper::Plugins::IdentityMap.models.clear
|
45
44
|
end
|
46
45
|
end
|
data/lib/mongo_mapper/version.rb
CHANGED
@@ -102,6 +102,21 @@ class BelongsToProxyTest < Test::Unit::TestCase
|
|
102
102
|
@comment_class.new(:name => 'Foo', :post_id => id).post.nil?.should be_true
|
103
103
|
end
|
104
104
|
|
105
|
+
should "define foreign key if it doesn't exist" do
|
106
|
+
@category_class = Doc()
|
107
|
+
@post_class.belongs_to :category, :class => @category_class
|
108
|
+
|
109
|
+
@post_class.key?(:category_id).should be_true
|
110
|
+
end
|
111
|
+
|
112
|
+
should "not define foreign key if it already exists" do
|
113
|
+
@category_class = Doc()
|
114
|
+
@post_class.key :category_id, String
|
115
|
+
@post_class.belongs_to :category, :class => @category_class
|
116
|
+
|
117
|
+
@post_class.keys['category_id'].type.should == String
|
118
|
+
end
|
119
|
+
|
105
120
|
context ":dependent" do
|
106
121
|
setup do
|
107
122
|
# FIXME: make use of already defined models
|