mongo_mapper 0.8.6 → 0.9.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 +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
|