mongo_mapper 0.13.1 → 0.14.0.rc1
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.
- checksums.yaml +13 -5
- data/README.rdoc +3 -6
- data/lib/mongo_mapper.rb +1 -0
- data/lib/mongo_mapper/document.rb +2 -0
- data/lib/mongo_mapper/extensions/array.rb +14 -6
- data/lib/mongo_mapper/extensions/hash.rb +15 -3
- data/lib/mongo_mapper/extensions/object.rb +4 -0
- data/lib/mongo_mapper/extensions/string.rb +13 -5
- data/lib/mongo_mapper/plugins/accessible.rb +12 -11
- data/lib/mongo_mapper/plugins/associations.rb +7 -6
- data/lib/mongo_mapper/plugins/associations/base.rb +13 -12
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +9 -8
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +12 -11
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +4 -4
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +24 -23
- data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +18 -16
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +55 -48
- data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +14 -13
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +7 -6
- data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +7 -5
- data/lib/mongo_mapper/plugins/associations/one_as_proxy.rb +14 -11
- data/lib/mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb +14 -13
- data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +9 -9
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +27 -26
- data/lib/mongo_mapper/plugins/associations/proxy.rb +29 -26
- data/lib/mongo_mapper/plugins/callbacks.rb +13 -0
- data/lib/mongo_mapper/plugins/counter_cache.rb +23 -4
- data/lib/mongo_mapper/plugins/dirty.rb +2 -2
- data/lib/mongo_mapper/plugins/dynamic_querying.rb +10 -9
- data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +17 -16
- data/lib/mongo_mapper/plugins/embedded_callbacks.rb +1 -1
- data/lib/mongo_mapper/plugins/identity_map.rb +1 -1
- data/lib/mongo_mapper/plugins/indexes.rb +1 -1
- data/lib/mongo_mapper/plugins/keys.rb +158 -158
- data/lib/mongo_mapper/plugins/keys/key.rb +16 -10
- data/lib/mongo_mapper/plugins/keys/static.rb +45 -0
- data/lib/mongo_mapper/plugins/modifiers.rb +27 -26
- data/lib/mongo_mapper/plugins/partial_updates.rb +86 -0
- data/lib/mongo_mapper/plugins/persistence.rb +7 -6
- data/lib/mongo_mapper/plugins/protected.rb +6 -5
- data/lib/mongo_mapper/plugins/querying.rb +80 -43
- data/lib/mongo_mapper/plugins/querying/decorated_plucky_query.rb +14 -9
- data/lib/mongo_mapper/plugins/scopes.rb +78 -7
- data/lib/mongo_mapper/plugins/timestamps.rb +1 -0
- data/lib/mongo_mapper/plugins/validations.rb +0 -0
- data/lib/mongo_mapper/version.rb +1 -1
- data/lib/rails/generators/mongo_mapper/config/config_generator.rb +12 -13
- data/lib/rails/generators/mongo_mapper/model/model_generator.rb +9 -9
- data/spec/functional/accessible_spec.rb +12 -12
- data/spec/functional/associations/belongs_to_polymorphic_proxy_spec.rb +11 -11
- data/spec/functional/associations/belongs_to_proxy_spec.rb +14 -15
- data/spec/functional/associations/in_array_proxy_spec.rb +6 -6
- data/spec/functional/associations/many_documents_proxy_spec.rb +89 -18
- data/spec/functional/associations/many_embedded_polymorphic_proxy_spec.rb +11 -11
- data/spec/functional/associations/many_embedded_proxy_spec.rb +1 -1
- data/spec/functional/associations/one_as_proxy_spec.rb +14 -14
- data/spec/functional/associations/one_embedded_polymorphic_proxy_spec.rb +9 -9
- data/spec/functional/associations/one_embedded_proxy_spec.rb +3 -3
- data/spec/functional/associations/one_proxy_spec.rb +14 -14
- data/spec/functional/caching_spec.rb +8 -8
- data/spec/functional/callbacks_spec.rb +87 -0
- data/spec/functional/counter_cache_spec.rb +89 -0
- data/spec/functional/dirty_spec.rb +41 -41
- data/spec/functional/document_spec.rb +3 -3
- data/spec/functional/embedded_document_spec.rb +18 -18
- data/spec/functional/identity_map_spec.rb +28 -15
- data/spec/functional/indexes_spec.rb +4 -4
- data/spec/functional/keys_spec.rb +12 -3
- data/spec/functional/logger_spec.rb +1 -1
- data/spec/functional/modifiers_spec.rb +2 -2
- data/spec/functional/partial_updates_spec.rb +577 -0
- data/spec/functional/protected_spec.rb +13 -13
- data/spec/functional/querying_spec.rb +11 -10
- data/spec/functional/safe_spec.rb +2 -2
- data/spec/functional/sci_spec.rb +3 -3
- data/spec/functional/scopes_spec.rb +234 -1
- data/spec/functional/static_keys_spec.rb +153 -0
- data/spec/functional/stats_spec.rb +0 -4
- data/spec/functional/touch_spec.rb +1 -1
- data/spec/functional/validations_spec.rb +59 -57
- data/spec/quality_spec.rb +1 -1
- data/spec/spec_helper.rb +7 -3
- data/spec/support/matchers.rb +4 -13
- data/spec/unit/associations/base_spec.rb +12 -12
- data/spec/unit/associations/belongs_to_association_spec.rb +2 -2
- data/spec/unit/associations/many_association_spec.rb +2 -2
- data/spec/unit/associations/one_association_spec.rb +2 -2
- data/spec/unit/associations/proxy_spec.rb +13 -15
- data/spec/unit/document_spec.rb +5 -5
- data/spec/unit/dynamic_finder_spec.rb +8 -8
- data/spec/unit/embedded_document_spec.rb +14 -14
- data/spec/unit/extensions_spec.rb +17 -17
- data/spec/unit/identity_map_middleware_spec.rb +5 -5
- data/spec/unit/key_spec.rb +24 -21
- data/spec/unit/keys_spec.rb +5 -5
- data/spec/unit/mongo_mapper_spec.rb +26 -26
- data/spec/unit/rails_spec.rb +2 -2
- data/spec/unit/serialization_spec.rb +1 -1
- data/spec/unit/time_zones_spec.rb +2 -2
- data/spec/unit/validations_spec.rb +28 -15
- metadata +16 -14
- data/lib/mongo_mapper/connections/10gen.rb +0 -0
- data/lib/mongo_mapper/connections/moped.rb +0 -0
@@ -93,6 +93,11 @@ module MongoMapper
|
|
93
93
|
!!@name.match(/\A[a-z_][a-z0-9_]*\z/i)
|
94
94
|
end
|
95
95
|
|
96
|
+
RESERVED_KEYS = %w( id class object_id )
|
97
|
+
def reserved_name?
|
98
|
+
RESERVED_KEYS.include?(@name)
|
99
|
+
end
|
100
|
+
|
96
101
|
def read_accessor?
|
97
102
|
any_accessor? ["read"]
|
98
103
|
end
|
@@ -111,18 +116,19 @@ module MongoMapper
|
|
111
116
|
return !(@accessors & arr_opt).empty?
|
112
117
|
end
|
113
118
|
|
114
|
-
|
115
|
-
def typecast_class
|
116
|
-
@typecast_class ||= options[:typecast].constantize
|
117
|
-
end
|
119
|
+
private
|
118
120
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
121
|
+
def typecast_class
|
122
|
+
@typecast_class ||= options[:typecast].constantize
|
123
|
+
end
|
124
|
+
|
125
|
+
def validate_key_name!
|
126
|
+
if reserved_name?
|
127
|
+
raise MongoMapper::InvalidKey.new("`#{@name}` is a reserved key name (did you mean to use _id?)")
|
128
|
+
elsif !valid_ruby_name?
|
129
|
+
raise MongoMapper::InvalidKey.new("`#{@name}` is not a valid key name. Keys must match [a-z][a-z0-9_]*")
|
125
130
|
end
|
131
|
+
end
|
126
132
|
end
|
127
133
|
end
|
128
134
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Keys
|
4
|
+
module Static
|
5
|
+
class MissingKeyError < StandardError; end
|
6
|
+
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
attr_writer :static_keys
|
11
|
+
|
12
|
+
def static_keys
|
13
|
+
@static_keys || false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def read_key(name)
|
18
|
+
if !self.class.static_keys || self.class.key?(name)
|
19
|
+
super
|
20
|
+
else
|
21
|
+
raise MissingKeyError, "Tried to read the key #{name.inspect}, but no key was defined. Either define key :#{name} or set self.static_keys = false"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def write_key(name, value)
|
28
|
+
if !self.class.static_keys || self.class.key?(name)
|
29
|
+
super
|
30
|
+
else
|
31
|
+
raise MissingKeyError, "Tried to write the key #{name.inspect}, but no key was defined. Either define key :#{name} or set self.static_keys = false"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def load_from_database(attrs, with_cast = false)
|
36
|
+
return super if !self.class.static_keys || !attrs.respond_to?(:each)
|
37
|
+
|
38
|
+
attrs = attrs.select { |key, _| self.class.key?(key) }
|
39
|
+
|
40
|
+
super(attrs, with_cast)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -76,37 +76,38 @@ module MongoMapper
|
|
76
76
|
collection.update(criteria, updates, args)
|
77
77
|
end
|
78
78
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
79
|
+
private
|
80
|
+
|
81
|
+
def modifier_update(modifier, args)
|
82
|
+
criteria, updates, options = criteria_and_keys_from_args(args)
|
83
|
+
if options
|
84
|
+
collection.update(criteria, {modifier => updates}, options.merge(:multi => true))
|
85
|
+
else
|
86
|
+
collection.update(criteria, {modifier => updates}, :multi => true)
|
87
87
|
end
|
88
|
+
end
|
88
89
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
98
|
-
upgrade_legacy_safe_usage!(options)
|
99
|
-
updates = dealias_keys updates
|
100
|
-
|
101
|
-
[criteria_hash(criteria).to_hash, updates, options]
|
90
|
+
def criteria_and_keys_from_args(args)
|
91
|
+
if args[0].is_a?(Hash)
|
92
|
+
criteria = args[0]
|
93
|
+
updates = args[1]
|
94
|
+
options = args[2]
|
95
|
+
else
|
96
|
+
criteria, (updates, options) = args.partition { |a| !a.is_a?(Hash) }
|
97
|
+
criteria = { :id => criteria }
|
102
98
|
end
|
99
|
+
upgrade_legacy_safe_usage!(options)
|
100
|
+
updates = dealias_keys updates
|
101
|
+
|
102
|
+
[criteria_hash(criteria).to_hash, updates, options]
|
103
|
+
end
|
103
104
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
105
|
+
def upgrade_legacy_safe_usage!(options)
|
106
|
+
if options and options.key?(:safe)
|
107
|
+
options.merge! Utils.get_safe_options(options)
|
108
|
+
options.delete :safe
|
109
109
|
end
|
110
|
+
end
|
110
111
|
end
|
111
112
|
|
112
113
|
def unset(*args)
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module PartialUpdates
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
class PartialUpdatesDisabledError < StandardError; end
|
7
|
+
|
8
|
+
included do
|
9
|
+
class_attribute :partial_updates
|
10
|
+
self.partial_updates = false
|
11
|
+
|
12
|
+
self.after_find :_reset_partial_updates_callback
|
13
|
+
self.after_save :_reset_partial_updates_callback
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(*)
|
17
|
+
_reset_partial_updates_callback
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
def fields_for_partial_update
|
22
|
+
raise PartialUpdatesDisabledError if !partial_updates
|
23
|
+
|
24
|
+
Hash.new.tap do |hash|
|
25
|
+
attrs = _dealiased_attributes
|
26
|
+
|
27
|
+
hash[:set_fields] = Array.new.tap do |array|
|
28
|
+
attrs.each do |key, value|
|
29
|
+
if !@_last_saved_attributes.include?(key) ||
|
30
|
+
@_last_saved_attributes[key] != value
|
31
|
+
array << key
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
hash[:unset_fields] = @_last_saved_attributes.keys - attrs.keys
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def _reset_partial_updates_callback
|
43
|
+
_reset_attributes_for_partial_update if partial_updates
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
def update(options={})
|
48
|
+
if partial_updates
|
49
|
+
super(options.merge(:persistence_method => :update))
|
50
|
+
else
|
51
|
+
super
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def save_to_collection(options={})
|
56
|
+
if partial_updates && options[:persistence_method] == :update
|
57
|
+
updates = fields_for_partial_update
|
58
|
+
|
59
|
+
set_fields = updates[:set_fields]
|
60
|
+
unset_fields = updates[:unset_fields]
|
61
|
+
|
62
|
+
if set_fields.any? || unset_fields.any?
|
63
|
+
set_fields.push("_id") if !set_fields.include?("_id")
|
64
|
+
end
|
65
|
+
|
66
|
+
options = options.merge({
|
67
|
+
:set_fields => set_fields,
|
68
|
+
:unset_fields => unset_fields
|
69
|
+
})
|
70
|
+
|
71
|
+
super(options)
|
72
|
+
else
|
73
|
+
super
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def _dealiased_attributes
|
78
|
+
self.class.dealias_keys(attributes)
|
79
|
+
end
|
80
|
+
|
81
|
+
def _reset_attributes_for_partial_update
|
82
|
+
@_last_saved_attributes = _dealiased_attributes._mongo_mapper_deep_copy_
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -58,13 +58,14 @@ module MongoMapper
|
|
58
58
|
database.collection(collection_name)
|
59
59
|
end
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
61
|
+
private
|
62
|
+
|
63
|
+
def assert_supported
|
64
|
+
@embeddable ||= embeddable?
|
65
|
+
if @embeddable
|
66
|
+
raise MongoMapper::NotSupported.new('This is not supported for embeddable documents at this time.')
|
67
67
|
end
|
68
|
+
end
|
68
69
|
end
|
69
70
|
|
70
71
|
def collection
|
@@ -35,11 +35,12 @@ module MongoMapper
|
|
35
35
|
super(filter_protected_attrs(attrs))
|
36
36
|
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
protected
|
39
|
+
|
40
|
+
def filter_protected_attrs(attrs)
|
41
|
+
return attrs if protected_attributes.blank? || attrs.blank?
|
42
|
+
attrs.dup.delete_if { |key, val| protected_attributes.include?(key.to_sym) }
|
43
|
+
end
|
43
44
|
end
|
44
45
|
end
|
45
46
|
end
|
@@ -61,41 +61,42 @@ module MongoMapper
|
|
61
61
|
Plucky::CriteriaHash.new(criteria, :object_ids => object_id_keys)
|
62
62
|
end
|
63
63
|
|
64
|
-
|
65
|
-
def transformer
|
66
|
-
@transformer ||= lambda { |doc| load(doc) }
|
67
|
-
end
|
64
|
+
private
|
68
65
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
docs.flatten.each do |attrs|
|
73
|
-
doc = new(attrs)
|
74
|
-
yield(doc)
|
75
|
-
instances << doc
|
76
|
-
end
|
77
|
-
instances.size == 1 ? instances[0] : instances
|
78
|
-
end
|
66
|
+
def transformer
|
67
|
+
@transformer ||= lambda { |doc| load(doc) }
|
68
|
+
end
|
79
69
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
70
|
+
def initialize_each(*docs)
|
71
|
+
instances = []
|
72
|
+
docs = [{}] if docs.blank?
|
73
|
+
docs.flatten.each do |attrs|
|
74
|
+
doc = new(attrs)
|
75
|
+
yield(doc)
|
76
|
+
instances << doc
|
77
|
+
end
|
78
|
+
instances.size == 1 ? instances[0] : instances
|
79
|
+
end
|
84
80
|
|
85
|
-
|
86
|
-
|
87
|
-
|
81
|
+
def update_single(id, attrs)
|
82
|
+
if id.blank? || attrs.blank? || !attrs.is_a?(Hash)
|
83
|
+
raise ArgumentError, "Updating a single document requires an id and a hash of attributes"
|
88
84
|
end
|
89
85
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
86
|
+
find(id).tap do |doc|
|
87
|
+
doc.update_attributes(attrs)
|
88
|
+
end
|
89
|
+
end
|
94
90
|
|
95
|
-
|
96
|
-
|
97
|
-
|
91
|
+
def update_multiple(docs)
|
92
|
+
unless docs.is_a?(Hash)
|
93
|
+
raise ArgumentError, "Updating multiple documents takes 1 argument and it must be hash"
|
98
94
|
end
|
95
|
+
|
96
|
+
instances = []
|
97
|
+
docs.each_pair { |id, attrs| instances << update(id, attrs) }
|
98
|
+
instances
|
99
|
+
end
|
99
100
|
end
|
100
101
|
|
101
102
|
def save(options={})
|
@@ -116,25 +117,61 @@ module MongoMapper
|
|
116
117
|
self.class.delete(id).tap { @_destroyed = true } if persisted?
|
117
118
|
end
|
118
119
|
|
119
|
-
|
120
|
-
def create_or_update(options={})
|
121
|
-
result = persisted? ? update(options) : create(options)
|
122
|
-
result != false
|
123
|
-
end
|
120
|
+
private
|
124
121
|
|
125
|
-
|
126
|
-
|
127
|
-
|
122
|
+
def create_or_update(options={})
|
123
|
+
result = persisted? ? update(options) : create(options)
|
124
|
+
result != false
|
125
|
+
end
|
128
126
|
|
129
|
-
|
130
|
-
|
131
|
-
|
127
|
+
def create(options={})
|
128
|
+
save_to_collection(options.merge(:persistence_method => :insert))
|
129
|
+
end
|
130
|
+
|
131
|
+
def update(options={})
|
132
|
+
save_to_collection(options.reverse_merge(:persistence_method => :save))
|
133
|
+
end
|
134
|
+
|
135
|
+
def save_to_collection(options={})
|
136
|
+
@_new = false
|
137
|
+
method = options.delete(:persistence_method) || :save
|
138
|
+
update = to_mongo
|
139
|
+
query_options = Utils.get_safe_options(options)
|
132
140
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
141
|
+
case method
|
142
|
+
when :insert
|
143
|
+
collection.insert(update, query_options)
|
144
|
+
when :save
|
145
|
+
collection.save(update, query_options)
|
146
|
+
when :update
|
147
|
+
update.stringify_keys!
|
148
|
+
|
149
|
+
id = update.delete("_id")
|
150
|
+
|
151
|
+
set_values = update
|
152
|
+
unset_values = {}
|
153
|
+
|
154
|
+
if fields_for_set = options.delete(:set_fields)
|
155
|
+
set_values = set_values.slice(*fields_for_set)
|
156
|
+
end
|
157
|
+
|
158
|
+
if fields_for_unset = options.delete(:unset_fields)
|
159
|
+
fields_for_unset.each do |field|
|
160
|
+
unset_values[field] = true
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
find_query = { :_id => id }
|
165
|
+
|
166
|
+
update_query = {}
|
167
|
+
update_query["$set"] = set_values if set_values.any?
|
168
|
+
update_query["$unset"] = unset_values if unset_values.any?
|
169
|
+
|
170
|
+
if update_query.any?
|
171
|
+
collection.update(find_query, update_query, query_options)
|
172
|
+
end
|
137
173
|
end
|
174
|
+
end
|
138
175
|
end
|
139
176
|
end
|
140
177
|
end
|
@@ -58,17 +58,22 @@ module MongoMapper
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
|
61
|
+
private
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
else
|
69
|
-
result
|
70
|
-
end
|
63
|
+
def method_missing(method, *args, &block)
|
64
|
+
return super unless model.respond_to?(method)
|
65
|
+
|
66
|
+
result = model.with_scope(criteria_hash) do
|
67
|
+
model.send(method, *args, &block)
|
71
68
|
end
|
69
|
+
|
70
|
+
case result
|
71
|
+
when Plucky::Query
|
72
|
+
merge(result)
|
73
|
+
else
|
74
|
+
result
|
75
|
+
end
|
76
|
+
end
|
72
77
|
end
|
73
78
|
end
|
74
79
|
end
|