mongo_mapper 0.13.0.beta2 → 0.15.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.
- checksums.yaml +5 -5
- data/LICENSE +1 -1
- data/README.md +64 -0
- data/examples/keys.rb +3 -3
- data/examples/modifiers/set.rb +2 -2
- data/examples/querying.rb +3 -3
- data/examples/safe.rb +2 -2
- data/examples/scopes.rb +1 -1
- data/lib/mongo_mapper.rb +5 -0
- data/lib/mongo_mapper/connection.rb +16 -37
- data/lib/mongo_mapper/document.rb +4 -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/object_id.rb +5 -1
- data/lib/mongo_mapper/extensions/string.rb +13 -5
- data/lib/mongo_mapper/extensions/symbol.rb +18 -0
- data/lib/mongo_mapper/plugins/accessible.rb +14 -4
- data/lib/mongo_mapper/plugins/associations.rb +7 -6
- data/lib/mongo_mapper/plugins/associations/base.rb +18 -13
- data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +10 -1
- 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 +17 -14
- 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 +31 -28
- data/lib/mongo_mapper/plugins/callbacks.rb +14 -1
- data/lib/mongo_mapper/plugins/counter_cache.rb +97 -0
- data/lib/mongo_mapper/plugins/dirty.rb +29 -37
- data/lib/mongo_mapper/plugins/document.rb +1 -1
- data/lib/mongo_mapper/plugins/dynamic_querying.rb +10 -9
- data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +18 -17
- data/lib/mongo_mapper/plugins/embedded_callbacks.rb +2 -1
- data/lib/mongo_mapper/plugins/embedded_document.rb +1 -1
- data/lib/mongo_mapper/plugins/identity_map.rb +1 -1
- data/lib/mongo_mapper/plugins/indexes.rb +37 -2
- data/lib/mongo_mapper/plugins/keys.rb +202 -142
- data/lib/mongo_mapper/plugins/keys/key.rb +22 -13
- data/lib/mongo_mapper/plugins/keys/static.rb +45 -0
- data/lib/mongo_mapper/plugins/modifiers.rb +59 -28
- data/lib/mongo_mapper/plugins/partial_updates.rb +86 -0
- data/lib/mongo_mapper/plugins/persistence.rb +13 -8
- data/lib/mongo_mapper/plugins/protected.rb +6 -5
- data/lib/mongo_mapper/plugins/querying.rb +85 -42
- data/lib/mongo_mapper/plugins/querying/decorated_plucky_query.rb +32 -9
- data/lib/mongo_mapper/plugins/rails.rb +1 -0
- data/lib/mongo_mapper/plugins/safe.rb +10 -4
- data/lib/mongo_mapper/plugins/sci.rb +4 -1
- data/lib/mongo_mapper/plugins/scopes.rb +78 -7
- data/lib/mongo_mapper/plugins/stats.rb +17 -0
- data/lib/mongo_mapper/plugins/timestamps.rb +1 -0
- data/lib/mongo_mapper/plugins/touch.rb +1 -1
- data/lib/mongo_mapper/plugins/validations.rb +7 -2
- data/lib/mongo_mapper/railtie.rb +20 -0
- data/lib/mongo_mapper/railtie/database.rake +1 -1
- data/lib/mongo_mapper/utils.rb +2 -2
- 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/examples.txt +1643 -0
- data/spec/functional/accessible_spec.rb +13 -13
- data/spec/functional/associations/belongs_to_polymorphic_proxy_spec.rb +13 -13
- data/spec/functional/associations/belongs_to_proxy_spec.rb +18 -19
- data/spec/functional/associations/in_array_proxy_spec.rb +10 -10
- data/spec/functional/associations/many_documents_as_proxy_spec.rb +6 -6
- data/spec/functional/associations/many_documents_proxy_spec.rb +85 -14
- data/spec/functional/associations/many_embedded_polymorphic_proxy_spec.rb +13 -13
- data/spec/functional/associations/many_embedded_proxy_spec.rb +1 -1
- data/spec/functional/associations/many_polymorphic_proxy_spec.rb +4 -4
- data/spec/functional/associations/one_as_proxy_spec.rb +10 -10
- 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 +10 -10
- data/spec/functional/associations_spec.rb +3 -3
- data/spec/functional/binary_spec.rb +2 -2
- data/spec/functional/caching_spec.rb +8 -15
- data/spec/functional/callbacks_spec.rb +89 -2
- data/spec/functional/counter_cache_spec.rb +235 -0
- data/spec/functional/dirty_spec.rb +63 -46
- data/spec/functional/document_spec.rb +30 -2
- data/spec/functional/dumpable_spec.rb +1 -1
- data/spec/functional/embedded_document_spec.rb +18 -18
- data/spec/functional/identity_map_spec.rb +27 -14
- data/spec/functional/indexes_spec.rb +44 -19
- data/spec/functional/keys_spec.rb +117 -15
- data/spec/functional/logger_spec.rb +3 -3
- data/spec/functional/modifiers_spec.rb +67 -19
- data/spec/functional/partial_updates_spec.rb +577 -0
- data/spec/functional/protected_spec.rb +14 -14
- data/spec/functional/querying_spec.rb +55 -28
- data/spec/functional/safe_spec.rb +23 -27
- data/spec/functional/sci_spec.rb +49 -14
- data/spec/functional/scopes_spec.rb +235 -2
- data/spec/functional/static_keys_spec.rb +153 -0
- data/spec/functional/stats_spec.rb +86 -0
- data/spec/functional/touch_spec.rb +6 -6
- data/spec/functional/validations_spec.rb +51 -57
- data/spec/quality_spec.rb +51 -0
- data/spec/spec_helper.rb +37 -9
- data/spec/support/matchers.rb +5 -14
- 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 +19 -16
- data/spec/unit/clone_spec.rb +1 -1
- data/spec/unit/document_spec.rb +8 -8
- data/spec/unit/dynamic_finder_spec.rb +8 -8
- data/spec/unit/embedded_document_spec.rb +18 -19
- data/spec/unit/extensions_spec.rb +41 -17
- data/spec/unit/identity_map_middleware_spec.rb +65 -96
- data/spec/unit/inspect_spec.rb +4 -4
- data/spec/unit/key_spec.rb +28 -26
- data/spec/unit/keys_spec.rb +10 -10
- data/spec/unit/model_generator_spec.rb +2 -4
- data/spec/unit/mongo_mapper_spec.rb +38 -85
- data/spec/unit/rails_spec.rb +5 -0
- 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 +188 -161
- data/README.rdoc +0 -55
- data/lib/mongo_mapper/extensions/ordered_hash.rb +0 -23
@@ -62,7 +62,7 @@ module MongoMapper
|
|
62
62
|
|
63
63
|
if @typecast
|
64
64
|
klass = typecast_class # Don't make this lookup on every call
|
65
|
-
type.from_mongo(value).map
|
65
|
+
type.from_mongo(value).map { |v| klass.from_mongo(v) }
|
66
66
|
else
|
67
67
|
type.from_mongo(value)
|
68
68
|
end
|
@@ -71,8 +71,11 @@ module MongoMapper
|
|
71
71
|
def set(value)
|
72
72
|
# Avoid tap here so we don't have to create a block binding.
|
73
73
|
values = type.to_mongo(value)
|
74
|
-
|
75
|
-
|
74
|
+
if @typecast
|
75
|
+
values.map { |v| typecast_class.to_mongo(v) }
|
76
|
+
else
|
77
|
+
values
|
78
|
+
end
|
76
79
|
end
|
77
80
|
|
78
81
|
def default_value
|
@@ -90,6 +93,11 @@ module MongoMapper
|
|
90
93
|
!!@name.match(/\A[a-z_][a-z0-9_]*\z/i)
|
91
94
|
end
|
92
95
|
|
96
|
+
RESERVED_KEYS = %w( id class object_id )
|
97
|
+
def reserved_name?
|
98
|
+
RESERVED_KEYS.include?(@name)
|
99
|
+
end
|
100
|
+
|
93
101
|
def read_accessor?
|
94
102
|
any_accessor? ["read"]
|
95
103
|
end
|
@@ -108,18 +116,19 @@ module MongoMapper
|
|
108
116
|
return !(@accessors & arr_opt).empty?
|
109
117
|
end
|
110
118
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
119
|
+
private
|
120
|
+
|
121
|
+
def typecast_class
|
122
|
+
@typecast_class ||= options[:typecast].constantize
|
123
|
+
end
|
115
124
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
end
|
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_]*")
|
122
130
|
end
|
131
|
+
end
|
123
132
|
end
|
124
133
|
end
|
125
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
|
@@ -13,7 +13,7 @@ module MongoMapper
|
|
13
13
|
criteria, keys, options = criteria_and_keys_from_args(args)
|
14
14
|
values, to_decrement = keys.values, {}
|
15
15
|
keys.keys.each_with_index { |k, i| to_decrement[k] = -values[i].abs }
|
16
|
-
collection.
|
16
|
+
collection.update_many(criteria, {'$inc' => to_decrement}, options || {})
|
17
17
|
end
|
18
18
|
|
19
19
|
def set(*args)
|
@@ -44,7 +44,16 @@ module MongoMapper
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def push_all(*args)
|
47
|
-
|
47
|
+
Kernel.warn "push_all no longer supported. use $push with $each"
|
48
|
+
|
49
|
+
hash = args.pop
|
50
|
+
ids = args
|
51
|
+
|
52
|
+
push_values = hash.inject({}) do |hsh, (key, values)|
|
53
|
+
{ key => { '$each' => values } }
|
54
|
+
end
|
55
|
+
|
56
|
+
modifier_update('$addToSet', [ids, push_values].flatten)
|
48
57
|
end
|
49
58
|
|
50
59
|
def add_to_set(*args)
|
@@ -64,36 +73,52 @@ module MongoMapper
|
|
64
73
|
modifier_update('$pop', args)
|
65
74
|
end
|
66
75
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
76
|
+
def find_one_and_update(args)
|
77
|
+
args = args.dup
|
78
|
+
args[:query] = dealias_keys(args.delete :query) if args.key? :query
|
79
|
+
args[:update] = dealias_keys(args.delete :update) if args.key? :update
|
80
|
+
collection.find_one_and_update(args[:query], args[:update], args)
|
81
|
+
end
|
82
|
+
alias_method :find_and_modify, :find_one_and_update
|
83
|
+
|
84
|
+
def upsert(selector, updates, args = {})
|
85
|
+
criteria = dealias_keys(selector)
|
86
|
+
updates = dealias_keys(updates)
|
87
|
+
collection.update_one(criteria, updates, args.merge(upsert: true))
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def modifier_update(modifier, args)
|
93
|
+
criteria, updates, options = criteria_and_keys_from_args(args)
|
94
|
+
if options
|
95
|
+
collection.update_many(criteria, {modifier => updates}, options)
|
96
|
+
else
|
97
|
+
collection.update_many(criteria, {modifier => updates})
|
75
98
|
end
|
99
|
+
end
|
76
100
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
86
|
-
upgrade_legacy_safe_usage!(options)
|
87
|
-
|
88
|
-
[criteria_hash(criteria).to_hash, updates, options]
|
101
|
+
def criteria_and_keys_from_args(args)
|
102
|
+
if args[0].is_a?(Hash)
|
103
|
+
criteria = args[0]
|
104
|
+
updates = args[1]
|
105
|
+
options = args[2]
|
106
|
+
else
|
107
|
+
criteria, (updates, options) = args.partition { |a| !a.is_a?(Hash) }
|
108
|
+
criteria = { :id => criteria }
|
89
109
|
end
|
110
|
+
upgrade_legacy_safe_usage!(options)
|
111
|
+
updates = dealias_keys updates
|
112
|
+
|
113
|
+
[criteria_hash(criteria).to_hash, updates, options]
|
114
|
+
end
|
90
115
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
end
|
116
|
+
def upgrade_legacy_safe_usage!(options)
|
117
|
+
if options and options.key?(:safe)
|
118
|
+
options.merge! Utils.get_safe_options(options)
|
119
|
+
options.delete :safe
|
96
120
|
end
|
121
|
+
end
|
97
122
|
end
|
98
123
|
|
99
124
|
def unset(*args)
|
@@ -117,7 +142,13 @@ module MongoMapper
|
|
117
142
|
end
|
118
143
|
|
119
144
|
def push_all(hash, options=nil)
|
120
|
-
|
145
|
+
Kernel.warn "push_all no longer supported. use $push with $each"
|
146
|
+
|
147
|
+
push_values = hash.inject({}) do |hsh, (key, values)|
|
148
|
+
{ key => { '$each' => values } }
|
149
|
+
end
|
150
|
+
|
151
|
+
self.class.push({:_id => id}, push_values, options)
|
121
152
|
end
|
122
153
|
|
123
154
|
def pull(hash, options=nil)
|
@@ -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
|
@@ -39,7 +39,7 @@ module MongoMapper
|
|
39
39
|
if database_name.nil?
|
40
40
|
MongoMapper.database
|
41
41
|
else
|
42
|
-
connection.
|
42
|
+
connection.use(database_name).database
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
@@ -55,16 +55,21 @@ module MongoMapper
|
|
55
55
|
|
56
56
|
def collection
|
57
57
|
assert_supported
|
58
|
-
database.collection(collection_name)
|
58
|
+
database.collection(collection_name, collection_options)
|
59
59
|
end
|
60
60
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
61
|
+
def collection_options
|
62
|
+
{}
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def assert_supported
|
68
|
+
@embeddable ||= embeddable?
|
69
|
+
if @embeddable
|
70
|
+
raise MongoMapper::NotSupported.new('This is not supported for embeddable documents at this time.')
|
67
71
|
end
|
72
|
+
end
|
68
73
|
end
|
69
74
|
|
70
75
|
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,67 @@ 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
|
-
|
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)
|
140
|
+
|
141
|
+
if query_options.any?
|
142
|
+
collection = self.collection.with(write: query_options)
|
143
|
+
else
|
144
|
+
collection = self.collection
|
131
145
|
end
|
132
146
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
147
|
+
case method
|
148
|
+
when :insert
|
149
|
+
collection.insert_one(update, query_options)
|
150
|
+
when :save
|
151
|
+
collection.update_one({:_id => _id}, update, query_options.merge(upsert: true))
|
152
|
+
when :update
|
153
|
+
update.stringify_keys!
|
154
|
+
|
155
|
+
id = update.delete("_id")
|
156
|
+
|
157
|
+
set_values = update
|
158
|
+
unset_values = {}
|
159
|
+
|
160
|
+
if fields_for_set = options.delete(:set_fields)
|
161
|
+
set_values = set_values.slice(*fields_for_set)
|
162
|
+
end
|
163
|
+
|
164
|
+
if fields_for_unset = options.delete(:unset_fields)
|
165
|
+
fields_for_unset.each do |field|
|
166
|
+
unset_values[field] = true
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
find_query = { :_id => id }
|
171
|
+
|
172
|
+
update_query = {}
|
173
|
+
update_query["$set"] = set_values if set_values.any?
|
174
|
+
update_query["$unset"] = unset_values if unset_values.any?
|
175
|
+
|
176
|
+
if update_query.any?
|
177
|
+
collection.update_one(find_query, update_query, query_options)
|
178
|
+
end
|
137
179
|
end
|
180
|
+
end
|
138
181
|
end
|
139
182
|
end
|
140
183
|
end
|