mongo_mapper 0.8.6 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/UPGRADES +10 -0
- data/bin/mmconsole +0 -1
- data/examples/identity_map/automatic.rb +1 -7
- data/examples/plugins.rb +9 -9
- data/examples/safe.rb +43 -0
- data/lib/mongo_mapper.rb +46 -33
- data/lib/mongo_mapper/document.rb +33 -32
- data/lib/mongo_mapper/embedded_document.rb +22 -22
- data/lib/mongo_mapper/locale/en.yml +5 -0
- data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
- data/lib/mongo_mapper/plugins.rb +16 -3
- data/lib/mongo_mapper/plugins/accessible.rb +2 -0
- data/lib/mongo_mapper/plugins/active_model.rb +18 -0
- data/lib/mongo_mapper/plugins/associations.rb +37 -42
- data/lib/mongo_mapper/plugins/associations/base.rb +14 -50
- data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +58 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +6 -1
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +30 -2
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +4 -0
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +12 -6
- data/lib/mongo_mapper/plugins/associations/many_association.rb +67 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +5 -5
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +1 -1
- data/lib/mongo_mapper/plugins/associations/one_association.rb +20 -0
- data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +5 -0
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +7 -7
- data/lib/mongo_mapper/plugins/associations/proxy.rb +2 -2
- data/lib/mongo_mapper/plugins/caching.rb +3 -1
- data/lib/mongo_mapper/plugins/callbacks.rb +12 -221
- data/lib/mongo_mapper/plugins/clone.rb +3 -1
- data/lib/mongo_mapper/plugins/dirty.rb +38 -91
- data/lib/mongo_mapper/plugins/document.rb +4 -2
- data/lib/mongo_mapper/plugins/dynamic_querying.rb +2 -0
- data/lib/mongo_mapper/plugins/embedded_callbacks.rb +43 -0
- data/lib/mongo_mapper/plugins/embedded_document.rb +16 -9
- data/lib/mongo_mapper/plugins/equality.rb +2 -0
- data/lib/mongo_mapper/plugins/identity_map.rb +4 -2
- data/lib/mongo_mapper/plugins/indexes.rb +2 -0
- data/lib/mongo_mapper/plugins/inspect.rb +3 -1
- data/lib/mongo_mapper/plugins/keys.rb +28 -22
- data/lib/mongo_mapper/plugins/keys/key.rb +12 -6
- data/lib/mongo_mapper/plugins/logger.rb +2 -0
- data/lib/mongo_mapper/plugins/modifiers.rb +3 -1
- data/lib/mongo_mapper/plugins/pagination.rb +2 -0
- data/lib/mongo_mapper/plugins/persistence.rb +2 -0
- data/lib/mongo_mapper/plugins/protected.rb +2 -0
- data/lib/mongo_mapper/plugins/querying.rb +5 -4
- data/lib/mongo_mapper/plugins/rails.rb +3 -5
- data/lib/mongo_mapper/plugins/safe.rb +2 -0
- data/lib/mongo_mapper/plugins/sci.rb +2 -0
- data/lib/mongo_mapper/plugins/scopes.rb +2 -0
- data/lib/mongo_mapper/plugins/serialization.rb +67 -46
- data/lib/mongo_mapper/plugins/timestamps.rb +3 -1
- data/lib/mongo_mapper/plugins/userstamps.rb +2 -0
- data/lib/mongo_mapper/plugins/validations.rb +40 -24
- data/lib/mongo_mapper/railtie.rb +49 -0
- data/lib/mongo_mapper/railtie/database.rake +60 -0
- data/lib/mongo_mapper/support/descendant_appends.rb +11 -11
- data/lib/mongo_mapper/translation.rb +10 -0
- data/lib/mongo_mapper/version.rb +1 -1
- data/lib/rails/generators/mongo_mapper/config/config_generator.rb +24 -0
- data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +18 -0
- data/lib/rails/generators/mongo_mapper/model/model_generator.rb +23 -0
- data/lib/rails/generators/mongo_mapper/model/templates/model.rb +11 -0
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +1 -0
- data/test/functional/associations/test_belongs_to_proxy.rb +131 -1
- data/test/functional/associations/test_in_array_proxy.rb +30 -0
- data/test/functional/associations/test_many_documents_proxy.rb +30 -2
- data/test/functional/associations/test_many_embedded_proxy.rb +33 -0
- data/test/functional/associations/test_many_polymorphic_proxy.rb +1 -0
- data/test/functional/associations/test_one_embedded_proxy.rb +21 -2
- data/test/functional/associations/test_one_proxy.rb +49 -9
- data/test/functional/test_associations.rb +2 -0
- data/test/functional/test_caching.rb +3 -2
- data/test/functional/test_callbacks.rb +25 -18
- data/test/functional/test_dirty.rb +123 -1
- data/test/functional/test_document.rb +26 -2
- data/test/functional/test_embedded_document.rb +68 -2
- data/test/functional/test_identity_map.rb +3 -4
- data/test/functional/test_querying.rb +11 -0
- data/test/functional/test_userstamps.rb +2 -2
- data/test/functional/test_validations.rb +31 -29
- data/test/models.rb +10 -0
- data/test/test_active_model_lint.rb +1 -1
- data/test/test_helper.rb +9 -10
- data/test/unit/associations/test_base.rb +24 -100
- data/test/unit/associations/test_belongs_to_association.rb +29 -0
- data/test/unit/associations/test_many_association.rb +63 -0
- data/test/unit/associations/test_one_association.rb +18 -0
- data/test/unit/serializers/test_json_serializer.rb +0 -1
- data/test/unit/test_descendant_appends.rb +8 -16
- data/test/unit/test_document.rb +4 -9
- data/test/unit/test_dynamic_finder.rb +1 -1
- data/test/unit/test_embedded_document.rb +51 -18
- data/test/unit/test_identity_map_middleware.rb +34 -0
- data/test/unit/test_inspect.rb +22 -0
- data/test/unit/test_key.rb +21 -1
- data/test/unit/test_keys.rb +0 -2
- data/test/unit/test_plugins.rb +106 -20
- data/test/unit/test_rails.rb +8 -8
- data/test/unit/test_serialization.rb +116 -1
- data/test/unit/test_translation.rb +27 -0
- data/test/unit/test_validations.rb +66 -81
- metadata +103 -43
- data/examples/identity_map/middleware.rb +0 -14
- data/lib/mongo_mapper/plugins/descendants.rb +0 -17
- data/rails/init.rb +0 -19
@@ -3,47 +3,26 @@ module MongoMapper
|
|
3
3
|
module Plugins
|
4
4
|
module Associations
|
5
5
|
class Base
|
6
|
-
attr_reader :
|
6
|
+
attr_reader :name, :options, :query_options
|
7
7
|
|
8
8
|
# Options that should not be considered MongoDB query options/criteria
|
9
|
-
AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :polymorphic]
|
9
|
+
AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :polymorphic, :autosave]
|
10
10
|
|
11
|
-
def initialize(
|
12
|
-
@
|
11
|
+
def initialize(name, options={}, &extension)
|
12
|
+
@name, @options, @query_options, @original_options = name.to_sym, {}, {}, options
|
13
13
|
options.symbolize_keys!
|
14
14
|
options[:extend] = modularized_extensions(extension, options[:extend])
|
15
15
|
separate_options_and_conditions
|
16
16
|
end
|
17
17
|
|
18
18
|
def class_name
|
19
|
-
|
20
|
-
|
21
|
-
@class_name =
|
22
|
-
if cn = options[:class_name]
|
23
|
-
cn
|
24
|
-
elsif many?
|
25
|
-
name.to_s.singularize.camelize
|
26
|
-
else
|
27
|
-
name.to_s.camelize
|
28
|
-
end
|
19
|
+
@class_name ||= options[:class_name] || name.to_s.camelize
|
29
20
|
end
|
30
21
|
|
31
22
|
def klass
|
32
23
|
@klass ||= options[:class] || class_name.constantize
|
33
24
|
end
|
34
25
|
|
35
|
-
def many?
|
36
|
-
@type == :many
|
37
|
-
end
|
38
|
-
|
39
|
-
def belongs_to?
|
40
|
-
@type == :belongs_to
|
41
|
-
end
|
42
|
-
|
43
|
-
def one?
|
44
|
-
@type == :one
|
45
|
-
end
|
46
|
-
|
47
26
|
def polymorphic?
|
48
27
|
!!@options[:polymorphic]
|
49
28
|
end
|
@@ -57,11 +36,11 @@ module MongoMapper
|
|
57
36
|
end
|
58
37
|
|
59
38
|
def embeddable?
|
60
|
-
|
39
|
+
klass.embeddable?
|
61
40
|
end
|
62
41
|
|
63
42
|
def type_key_name
|
64
|
-
|
43
|
+
"#{as}_type"
|
65
44
|
end
|
66
45
|
|
67
46
|
def as
|
@@ -76,30 +55,15 @@ module MongoMapper
|
|
76
55
|
@ivar ||= "@_#{name}"
|
77
56
|
end
|
78
57
|
|
79
|
-
# hate this, need to revisit
|
80
58
|
def proxy_class
|
81
|
-
|
59
|
+
raise NotImplementedError
|
60
|
+
end
|
82
61
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
if polymorphic?
|
89
|
-
ManyPolymorphicProxy
|
90
|
-
elsif as?
|
91
|
-
ManyDocumentsAsProxy
|
92
|
-
elsif in_array?
|
93
|
-
InArrayProxy
|
94
|
-
else
|
95
|
-
ManyDocumentsProxy
|
96
|
-
end
|
97
|
-
end
|
98
|
-
elsif one?
|
99
|
-
klass.embeddable? ? OneEmbeddedProxy : OneProxy
|
100
|
-
else
|
101
|
-
polymorphic? ? BelongsToPolymorphicProxy : BelongsToProxy
|
102
|
-
end
|
62
|
+
def setup(model)
|
63
|
+
end
|
64
|
+
|
65
|
+
def autosave?
|
66
|
+
raise NotImplementedError
|
103
67
|
end
|
104
68
|
|
105
69
|
private
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module MongoMapper
|
3
|
+
module Plugins
|
4
|
+
module Associations
|
5
|
+
class BelongsToAssociation < Base
|
6
|
+
|
7
|
+
def embeddable?
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def proxy_class
|
12
|
+
@proxy_class ||= polymorphic? ? BelongsToPolymorphicProxy : BelongsToProxy
|
13
|
+
end
|
14
|
+
|
15
|
+
def setup(model)
|
16
|
+
model.associations_module.module_eval <<-end_eval
|
17
|
+
def #{name}
|
18
|
+
proxy = get_proxy(associations[#{name.inspect}])
|
19
|
+
proxy.nil? ? nil : proxy
|
20
|
+
end
|
21
|
+
|
22
|
+
def #{name}=(value)
|
23
|
+
association = associations[#{name.inspect}]
|
24
|
+
proxy = get_proxy(association)
|
25
|
+
|
26
|
+
if proxy.nil? || proxy.target != value
|
27
|
+
proxy = build_proxy(association)
|
28
|
+
end
|
29
|
+
|
30
|
+
proxy.replace(value)
|
31
|
+
value
|
32
|
+
end
|
33
|
+
|
34
|
+
def #{name}?
|
35
|
+
get_proxy(associations[#{name.inspect}]).present?
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_#{name}(attrs={})
|
39
|
+
get_proxy(associations[#{name.inspect}]).build(attrs)
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_#{name}(attrs={})
|
43
|
+
get_proxy(associations[#{name.inspect}]).create(attrs)
|
44
|
+
end
|
45
|
+
|
46
|
+
def create_#{name}!(attrs={})
|
47
|
+
get_proxy(associations[#{name.inspect}]).create!(attrs)
|
48
|
+
end
|
49
|
+
end_eval
|
50
|
+
end
|
51
|
+
|
52
|
+
def autosave?
|
53
|
+
options.fetch(:autosave, false)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -5,13 +5,18 @@ module MongoMapper
|
|
5
5
|
class BelongsToPolymorphicProxy < Proxy
|
6
6
|
def replace(doc)
|
7
7
|
if doc
|
8
|
-
doc.save
|
8
|
+
doc.save unless doc.persisted?
|
9
9
|
id, type = doc.id, doc.class.name
|
10
10
|
end
|
11
11
|
|
12
12
|
proxy_owner[association.foreign_key] = id
|
13
13
|
proxy_owner[association.type_key_name] = type
|
14
14
|
reset
|
15
|
+
unless doc.nil?
|
16
|
+
loaded
|
17
|
+
@target = doc
|
18
|
+
end
|
19
|
+
@target
|
15
20
|
end
|
16
21
|
|
17
22
|
protected
|
@@ -5,12 +5,33 @@ module MongoMapper
|
|
5
5
|
class BelongsToProxy < Proxy
|
6
6
|
def replace(doc)
|
7
7
|
if doc
|
8
|
-
doc.save if doc.
|
8
|
+
doc.save if !doc.persisted?
|
9
9
|
id = doc.id
|
10
10
|
end
|
11
11
|
|
12
|
+
reset
|
12
13
|
proxy_owner[association.foreign_key] = id
|
13
|
-
|
14
|
+
unless doc.nil?
|
15
|
+
loaded
|
16
|
+
@target = doc
|
17
|
+
end
|
18
|
+
@target
|
19
|
+
end
|
20
|
+
|
21
|
+
def build(attrs={})
|
22
|
+
instantiate_target(:new, attrs)
|
23
|
+
end
|
24
|
+
|
25
|
+
def create(attrs={})
|
26
|
+
instantiate_target(:create, attrs)
|
27
|
+
end
|
28
|
+
|
29
|
+
def create!(attrs={})
|
30
|
+
instantiate_target(:create!, attrs)
|
31
|
+
end
|
32
|
+
|
33
|
+
def save_to_collection(options={})
|
34
|
+
@target.save(options) if @target
|
14
35
|
end
|
15
36
|
|
16
37
|
protected
|
@@ -18,6 +39,13 @@ module MongoMapper
|
|
18
39
|
return nil if proxy_owner[association.foreign_key].nil?
|
19
40
|
klass.find_by_id(proxy_owner[association.foreign_key])
|
20
41
|
end
|
42
|
+
|
43
|
+
def instantiate_target(instantiator, attrs={})
|
44
|
+
@target = klass.send(instantiator, attrs)
|
45
|
+
proxy_owner[association.foreign_key] = @target.id
|
46
|
+
loaded
|
47
|
+
@target
|
48
|
+
end
|
21
49
|
end
|
22
50
|
end
|
23
51
|
end
|
@@ -30,6 +30,10 @@ module MongoMapper
|
|
30
30
|
alias_method :push, :<<
|
31
31
|
alias_method :concat, :<<
|
32
32
|
|
33
|
+
def save_to_collection(options={})
|
34
|
+
@target.each { |doc| doc.persist(options) } if @target
|
35
|
+
end
|
36
|
+
|
33
37
|
private
|
34
38
|
def assign_references(*docs)
|
35
39
|
docs.each { |doc| doc._parent_document = proxy_owner }
|
@@ -14,22 +14,27 @@ module MongoMapper
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def paginate(options)
|
17
|
+
return [] if ids.blank?
|
17
18
|
query.paginate(options)
|
18
19
|
end
|
19
20
|
|
20
21
|
def all(options={})
|
22
|
+
return [] if ids.blank?
|
21
23
|
query(options).all
|
22
24
|
end
|
23
25
|
|
24
26
|
def first(options={})
|
27
|
+
return nil if ids.blank?
|
25
28
|
query(options).first
|
26
29
|
end
|
27
30
|
|
28
31
|
def last(options={})
|
32
|
+
return nil if ids.blank?
|
29
33
|
query(options).last
|
30
34
|
end
|
31
35
|
|
32
36
|
def count(options={})
|
37
|
+
return 0 if ids.blank?
|
33
38
|
options.blank? ? ids.size : query(options).count
|
34
39
|
end
|
35
40
|
|
@@ -44,7 +49,7 @@ module MongoMapper
|
|
44
49
|
def delete_all(options={})
|
45
50
|
docs = query(options).fields(:_id).all
|
46
51
|
docs.each { |doc| ids.delete(doc.id) }
|
47
|
-
klass.delete(docs.map
|
52
|
+
klass.delete(docs.map { |d| d.id })
|
48
53
|
reset
|
49
54
|
end
|
50
55
|
|
@@ -55,7 +60,7 @@ module MongoMapper
|
|
55
60
|
|
56
61
|
def create(attrs={})
|
57
62
|
doc = klass.create(attrs)
|
58
|
-
|
63
|
+
if doc.persisted?
|
59
64
|
ids << doc.id
|
60
65
|
proxy_owner.save
|
61
66
|
reset
|
@@ -65,7 +70,7 @@ module MongoMapper
|
|
65
70
|
|
66
71
|
def create!(attrs={})
|
67
72
|
doc = klass.create!(attrs)
|
68
|
-
|
73
|
+
if doc.persisted?
|
69
74
|
ids << doc.id
|
70
75
|
proxy_owner.save
|
71
76
|
reset
|
@@ -75,7 +80,7 @@ module MongoMapper
|
|
75
80
|
|
76
81
|
def <<(*docs)
|
77
82
|
flatten_deeper(docs).each do |doc|
|
78
|
-
doc.save
|
83
|
+
doc.save unless doc.persisted?
|
79
84
|
unless ids.include?(doc.id)
|
80
85
|
ids << doc.id
|
81
86
|
end
|
@@ -87,7 +92,7 @@ module MongoMapper
|
|
87
92
|
|
88
93
|
def replace(docs)
|
89
94
|
doc_ids = docs.map do |doc|
|
90
|
-
doc.save
|
95
|
+
doc.save unless doc.persisted?
|
91
96
|
doc.id
|
92
97
|
end
|
93
98
|
ids.replace(doc_ids.uniq)
|
@@ -115,7 +120,8 @@ module MongoMapper
|
|
115
120
|
end
|
116
121
|
|
117
122
|
def find_target
|
118
|
-
|
123
|
+
return [] if ids.blank?
|
124
|
+
all
|
119
125
|
end
|
120
126
|
|
121
127
|
def ids
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module MongoMapper
|
3
|
+
module Plugins
|
4
|
+
module Associations
|
5
|
+
class ManyAssociation < Base
|
6
|
+
|
7
|
+
def class_name
|
8
|
+
@class_name ||= options[:class_name] || name.to_s.singularize.camelize
|
9
|
+
end
|
10
|
+
|
11
|
+
def type_key_name
|
12
|
+
"_type"
|
13
|
+
end
|
14
|
+
|
15
|
+
# hate this, need to revisit
|
16
|
+
def proxy_class
|
17
|
+
@proxy_class ||= if klass.embeddable?
|
18
|
+
polymorphic? ? ManyEmbeddedPolymorphicProxy : ManyEmbeddedProxy
|
19
|
+
else
|
20
|
+
if polymorphic?
|
21
|
+
ManyPolymorphicProxy
|
22
|
+
elsif as?
|
23
|
+
ManyDocumentsAsProxy
|
24
|
+
elsif in_array?
|
25
|
+
InArrayProxy
|
26
|
+
else
|
27
|
+
ManyDocumentsProxy
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def setup(model)
|
33
|
+
model.associations_module.module_eval <<-end_eval
|
34
|
+
def #{name}
|
35
|
+
get_proxy(associations[#{name.inspect}])
|
36
|
+
end
|
37
|
+
|
38
|
+
def #{name}=(value)
|
39
|
+
get_proxy(associations[#{name.inspect}]).replace(value)
|
40
|
+
value
|
41
|
+
end
|
42
|
+
end_eval
|
43
|
+
|
44
|
+
if options[:dependent] && !embeddable?
|
45
|
+
association = self
|
46
|
+
options = self.options
|
47
|
+
|
48
|
+
model.after_destroy do
|
49
|
+
case options[:dependent]
|
50
|
+
when :destroy
|
51
|
+
self.get_proxy(association).destroy_all
|
52
|
+
when :delete_all
|
53
|
+
self.get_proxy(association).delete_all
|
54
|
+
when :nullify
|
55
|
+
self.get_proxy(association).nullify
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def autosave?
|
62
|
+
options.fetch(:autosave, true)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -8,7 +8,7 @@ module MongoMapper
|
|
8
8
|
|
9
9
|
def replace(docs)
|
10
10
|
load_target
|
11
|
-
target.
|
11
|
+
target.each { |t| t.destroy }
|
12
12
|
docs.each { |doc| prepare(doc).save }
|
13
13
|
reset
|
14
14
|
end
|
@@ -44,7 +44,7 @@ module MongoMapper
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def destroy_all(options={})
|
47
|
-
all(options).
|
47
|
+
all(options).each { |doc| doc.destroy }
|
48
48
|
reset
|
49
49
|
end
|
50
50
|
|
@@ -72,7 +72,7 @@ module MongoMapper
|
|
72
72
|
def method_missing(method, *args, &block)
|
73
73
|
if klass.respond_to?(method)
|
74
74
|
result = klass.send(method, *args, &block)
|
75
|
-
result.is_a?(Plucky::Query) ?
|
75
|
+
result.is_a?(Plucky::Query) ?
|
76
76
|
query.merge(result) : super
|
77
77
|
else
|
78
78
|
super
|
@@ -88,7 +88,7 @@ module MongoMapper
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def ensure_owner_saved
|
91
|
-
proxy_owner.save
|
91
|
+
proxy_owner.save unless proxy_owner.persisted?
|
92
92
|
end
|
93
93
|
|
94
94
|
def prepare(doc)
|
@@ -101,7 +101,7 @@ module MongoMapper
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def foreign_key
|
104
|
-
options[:foreign_key] || proxy_owner.class.name.
|
104
|
+
options[:foreign_key] || proxy_owner.class.name.foreign_key
|
105
105
|
end
|
106
106
|
end
|
107
107
|
end
|