mongo_mapper 0.13.0.beta2 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +1 -1
  3. data/README.md +64 -0
  4. data/examples/keys.rb +3 -3
  5. data/examples/modifiers/set.rb +2 -2
  6. data/examples/querying.rb +3 -3
  7. data/examples/safe.rb +2 -2
  8. data/examples/scopes.rb +1 -1
  9. data/lib/mongo_mapper.rb +5 -0
  10. data/lib/mongo_mapper/connection.rb +16 -37
  11. data/lib/mongo_mapper/document.rb +4 -0
  12. data/lib/mongo_mapper/extensions/array.rb +14 -6
  13. data/lib/mongo_mapper/extensions/hash.rb +15 -3
  14. data/lib/mongo_mapper/extensions/object.rb +4 -0
  15. data/lib/mongo_mapper/extensions/object_id.rb +5 -1
  16. data/lib/mongo_mapper/extensions/string.rb +13 -5
  17. data/lib/mongo_mapper/extensions/symbol.rb +18 -0
  18. data/lib/mongo_mapper/plugins/accessible.rb +14 -4
  19. data/lib/mongo_mapper/plugins/associations.rb +7 -6
  20. data/lib/mongo_mapper/plugins/associations/base.rb +18 -13
  21. data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +10 -1
  22. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +9 -8
  23. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +12 -11
  24. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +4 -4
  25. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +24 -23
  26. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +18 -16
  27. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +55 -48
  28. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +14 -13
  29. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +7 -6
  30. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +7 -5
  31. data/lib/mongo_mapper/plugins/associations/one_as_proxy.rb +17 -14
  32. data/lib/mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb +14 -13
  33. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +9 -9
  34. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +27 -26
  35. data/lib/mongo_mapper/plugins/associations/proxy.rb +31 -28
  36. data/lib/mongo_mapper/plugins/callbacks.rb +14 -1
  37. data/lib/mongo_mapper/plugins/counter_cache.rb +97 -0
  38. data/lib/mongo_mapper/plugins/dirty.rb +29 -37
  39. data/lib/mongo_mapper/plugins/document.rb +1 -1
  40. data/lib/mongo_mapper/plugins/dynamic_querying.rb +10 -9
  41. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +18 -17
  42. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +2 -1
  43. data/lib/mongo_mapper/plugins/embedded_document.rb +1 -1
  44. data/lib/mongo_mapper/plugins/identity_map.rb +1 -1
  45. data/lib/mongo_mapper/plugins/indexes.rb +37 -2
  46. data/lib/mongo_mapper/plugins/keys.rb +202 -142
  47. data/lib/mongo_mapper/plugins/keys/key.rb +22 -13
  48. data/lib/mongo_mapper/plugins/keys/static.rb +45 -0
  49. data/lib/mongo_mapper/plugins/modifiers.rb +59 -28
  50. data/lib/mongo_mapper/plugins/partial_updates.rb +86 -0
  51. data/lib/mongo_mapper/plugins/persistence.rb +13 -8
  52. data/lib/mongo_mapper/plugins/protected.rb +6 -5
  53. data/lib/mongo_mapper/plugins/querying.rb +85 -42
  54. data/lib/mongo_mapper/plugins/querying/decorated_plucky_query.rb +32 -9
  55. data/lib/mongo_mapper/plugins/rails.rb +1 -0
  56. data/lib/mongo_mapper/plugins/safe.rb +10 -4
  57. data/lib/mongo_mapper/plugins/sci.rb +4 -1
  58. data/lib/mongo_mapper/plugins/scopes.rb +78 -7
  59. data/lib/mongo_mapper/plugins/stats.rb +17 -0
  60. data/lib/mongo_mapper/plugins/timestamps.rb +1 -0
  61. data/lib/mongo_mapper/plugins/touch.rb +1 -1
  62. data/lib/mongo_mapper/plugins/validations.rb +7 -2
  63. data/lib/mongo_mapper/railtie.rb +20 -0
  64. data/lib/mongo_mapper/railtie/database.rake +1 -1
  65. data/lib/mongo_mapper/utils.rb +2 -2
  66. data/lib/mongo_mapper/version.rb +1 -1
  67. data/lib/rails/generators/mongo_mapper/config/config_generator.rb +12 -13
  68. data/lib/rails/generators/mongo_mapper/model/model_generator.rb +9 -9
  69. data/spec/examples.txt +1643 -0
  70. data/spec/functional/accessible_spec.rb +13 -13
  71. data/spec/functional/associations/belongs_to_polymorphic_proxy_spec.rb +13 -13
  72. data/spec/functional/associations/belongs_to_proxy_spec.rb +18 -19
  73. data/spec/functional/associations/in_array_proxy_spec.rb +10 -10
  74. data/spec/functional/associations/many_documents_as_proxy_spec.rb +6 -6
  75. data/spec/functional/associations/many_documents_proxy_spec.rb +85 -14
  76. data/spec/functional/associations/many_embedded_polymorphic_proxy_spec.rb +13 -13
  77. data/spec/functional/associations/many_embedded_proxy_spec.rb +1 -1
  78. data/spec/functional/associations/many_polymorphic_proxy_spec.rb +4 -4
  79. data/spec/functional/associations/one_as_proxy_spec.rb +10 -10
  80. data/spec/functional/associations/one_embedded_polymorphic_proxy_spec.rb +9 -9
  81. data/spec/functional/associations/one_embedded_proxy_spec.rb +3 -3
  82. data/spec/functional/associations/one_proxy_spec.rb +10 -10
  83. data/spec/functional/associations_spec.rb +3 -3
  84. data/spec/functional/binary_spec.rb +2 -2
  85. data/spec/functional/caching_spec.rb +8 -15
  86. data/spec/functional/callbacks_spec.rb +89 -2
  87. data/spec/functional/counter_cache_spec.rb +235 -0
  88. data/spec/functional/dirty_spec.rb +63 -46
  89. data/spec/functional/document_spec.rb +30 -2
  90. data/spec/functional/dumpable_spec.rb +1 -1
  91. data/spec/functional/embedded_document_spec.rb +18 -18
  92. data/spec/functional/identity_map_spec.rb +27 -14
  93. data/spec/functional/indexes_spec.rb +44 -19
  94. data/spec/functional/keys_spec.rb +117 -15
  95. data/spec/functional/logger_spec.rb +3 -3
  96. data/spec/functional/modifiers_spec.rb +67 -19
  97. data/spec/functional/partial_updates_spec.rb +577 -0
  98. data/spec/functional/protected_spec.rb +14 -14
  99. data/spec/functional/querying_spec.rb +55 -28
  100. data/spec/functional/safe_spec.rb +23 -27
  101. data/spec/functional/sci_spec.rb +49 -14
  102. data/spec/functional/scopes_spec.rb +235 -2
  103. data/spec/functional/static_keys_spec.rb +153 -0
  104. data/spec/functional/stats_spec.rb +86 -0
  105. data/spec/functional/touch_spec.rb +6 -6
  106. data/spec/functional/validations_spec.rb +51 -57
  107. data/spec/quality_spec.rb +51 -0
  108. data/spec/spec_helper.rb +37 -9
  109. data/spec/support/matchers.rb +5 -14
  110. data/spec/unit/associations/base_spec.rb +12 -12
  111. data/spec/unit/associations/belongs_to_association_spec.rb +2 -2
  112. data/spec/unit/associations/many_association_spec.rb +2 -2
  113. data/spec/unit/associations/one_association_spec.rb +2 -2
  114. data/spec/unit/associations/proxy_spec.rb +19 -16
  115. data/spec/unit/clone_spec.rb +1 -1
  116. data/spec/unit/document_spec.rb +8 -8
  117. data/spec/unit/dynamic_finder_spec.rb +8 -8
  118. data/spec/unit/embedded_document_spec.rb +18 -19
  119. data/spec/unit/extensions_spec.rb +41 -17
  120. data/spec/unit/identity_map_middleware_spec.rb +65 -96
  121. data/spec/unit/inspect_spec.rb +4 -4
  122. data/spec/unit/key_spec.rb +28 -26
  123. data/spec/unit/keys_spec.rb +10 -10
  124. data/spec/unit/model_generator_spec.rb +2 -4
  125. data/spec/unit/mongo_mapper_spec.rb +38 -85
  126. data/spec/unit/rails_spec.rb +5 -0
  127. data/spec/unit/serialization_spec.rb +1 -1
  128. data/spec/unit/time_zones_spec.rb +2 -2
  129. data/spec/unit/validations_spec.rb +28 -15
  130. metadata +188 -161
  131. data/README.rdoc +0 -55
  132. 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! { |v| klass.from_mongo(v) }
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
- values.map! { |v| typecast_class.to_mongo(v) } if @typecast
75
- values
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
- private
112
- def typecast_class
113
- @typecast_class ||= options[:typecast].constantize
114
- end
119
+ private
120
+
121
+ def typecast_class
122
+ @typecast_class ||= options[:typecast].constantize
123
+ end
115
124
 
116
- def validate_key_name!
117
- if %w( id ).include? @name
118
- raise MongoMapper::InvalidKey.new("`#{@name}` is a reserved key name (did you mean to use _id?)")
119
- elsif !valid_ruby_name?
120
- raise MongoMapper::InvalidKey.new("`#{@name}` is not a valid key name. Keys must match [a-z][a-z0-9_]*")
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.update(criteria, {'$inc' => to_decrement}, :multi => true)
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
- modifier_update('$pushAll', args)
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
- private
68
- def modifier_update(modifier, args)
69
- criteria, updates, options = criteria_and_keys_from_args(args)
70
- if options
71
- collection.update(criteria, {modifier => updates}, options.merge(:multi => true))
72
- else
73
- collection.update(criteria, {modifier => updates}, :multi => true)
74
- end
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
- def criteria_and_keys_from_args(args)
78
- if args[0].is_a?(Hash)
79
- criteria = args[0]
80
- updates = args[1]
81
- options = args[2]
82
- else
83
- criteria, (updates, options) = args.partition { |a| !a.is_a?(Hash) }
84
- criteria = { :id => criteria }
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
- def upgrade_legacy_safe_usage!(options)
92
- if options and options.key?(:safe)
93
- options.merge! Utils.get_safe_options(options)
94
- options.delete :safe
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
- self.class.push_all({:_id => id}, hash, options)
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.db(database_name)
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
- private
62
- def assert_supported
63
- @embeddable ||= embeddable?
64
- if @embeddable
65
- raise MongoMapper::NotSupported.new('This is not supported for embeddable documents at this time.')
66
- end
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
- protected
39
- def filter_protected_attrs(attrs)
40
- return attrs if protected_attributes.blank? || attrs.blank?
41
- attrs.dup.delete_if { |key, val| protected_attributes.include?(key.to_sym) }
42
- end
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
- private
65
- def transformer
66
- @transformer ||= lambda { |doc| load(doc) }
67
- end
64
+ private
68
65
 
69
- def initialize_each(*docs)
70
- instances = []
71
- docs = [{}] if docs.blank?
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
- def update_single(id, attrs)
81
- if id.blank? || attrs.blank? || !attrs.is_a?(Hash)
82
- raise ArgumentError, "Updating a single document requires an id and a hash of attributes"
83
- end
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
- find(id).tap do |doc|
86
- doc.update_attributes(attrs)
87
- end
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
- def update_multiple(docs)
91
- unless docs.is_a?(Hash)
92
- raise ArgumentError, "Updating multiple documents takes 1 argument and it must be hash"
93
- end
86
+ find(id).tap do |doc|
87
+ doc.update_attributes(attrs)
88
+ end
89
+ end
94
90
 
95
- instances = []
96
- docs.each_pair { |id, attrs| instances << update(id, attrs) }
97
- instances
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
- private
120
- def create_or_update(options={})
121
- result = persisted? ? update(options) : create(options)
122
- result != false
123
- end
120
+ private
124
121
 
125
- def create(options={})
126
- save_to_collection(options.merge(:persistence_method => :insert))
127
- end
122
+ def create_or_update(options={})
123
+ result = persisted? ? update(options) : create(options)
124
+ result != false
125
+ end
128
126
 
129
- def update(options={})
130
- save_to_collection(options.merge(:persistence_method => :save))
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
- def save_to_collection(options={})
134
- @_new = false
135
- method = options.delete(:persistence_method) || :save
136
- collection.send(method, to_mongo, Utils.get_safe_options(options))
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