pwnash-mongo_mapper 0.7.5 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/lib/mongo_mapper.rb +6 -8
  2. data/lib/mongo_mapper/document.rb +6 -281
  3. data/lib/mongo_mapper/embedded_document.rb +5 -45
  4. data/lib/mongo_mapper/extensions.rb +190 -0
  5. data/lib/mongo_mapper/plugins.rb +27 -18
  6. data/lib/mongo_mapper/plugins/associations.rb +7 -6
  7. data/lib/mongo_mapper/plugins/associations/base.rb +1 -0
  8. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +1 -0
  9. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +1 -0
  10. data/lib/mongo_mapper/plugins/associations/collection.rb +1 -0
  11. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +1 -0
  12. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +2 -1
  13. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +1 -0
  14. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +4 -4
  15. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +1 -0
  16. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +1 -0
  17. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +1 -0
  18. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +1 -0
  19. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +1 -0
  20. data/lib/mongo_mapper/plugins/associations/proxy.rb +1 -0
  21. data/lib/mongo_mapper/plugins/callbacks.rb +4 -3
  22. data/lib/mongo_mapper/plugins/clone.rb +1 -0
  23. data/lib/mongo_mapper/plugins/descendants.rb +1 -0
  24. data/lib/mongo_mapper/plugins/dirty.rb +1 -0
  25. data/lib/mongo_mapper/plugins/document.rb +40 -0
  26. data/lib/mongo_mapper/plugins/dynamic_querying.rb +42 -0
  27. data/lib/mongo_mapper/{support/find.rb → plugins/dynamic_querying/dynamic_finder.rb} +2 -36
  28. data/lib/mongo_mapper/plugins/embedded_document.rb +48 -0
  29. data/lib/mongo_mapper/plugins/equality.rb +1 -0
  30. data/lib/mongo_mapper/plugins/identity_map.rb +8 -11
  31. data/lib/mongo_mapper/plugins/indexes.rb +11 -0
  32. data/lib/mongo_mapper/plugins/inspect.rb +1 -0
  33. data/lib/mongo_mapper/plugins/keys.rb +7 -9
  34. data/lib/mongo_mapper/plugins/keys/key.rb +12 -2
  35. data/lib/mongo_mapper/plugins/logger.rb +1 -0
  36. data/lib/mongo_mapper/plugins/modifiers.rb +3 -2
  37. data/lib/mongo_mapper/plugins/pagination.rb +1 -0
  38. data/lib/mongo_mapper/plugins/pagination/proxy.rb +1 -0
  39. data/lib/mongo_mapper/plugins/persistence.rb +1 -0
  40. data/lib/mongo_mapper/plugins/protected.rb +1 -0
  41. data/lib/mongo_mapper/plugins/query_logger.rb +5 -10
  42. data/lib/mongo_mapper/plugins/querying.rb +236 -0
  43. data/lib/mongo_mapper/plugins/rails.rb +1 -0
  44. data/lib/mongo_mapper/plugins/sci.rb +31 -0
  45. data/lib/mongo_mapper/plugins/serialization.rb +1 -0
  46. data/lib/mongo_mapper/plugins/timestamps.rb +1 -0
  47. data/lib/mongo_mapper/plugins/userstamps.rb +1 -0
  48. data/lib/mongo_mapper/plugins/validations.rb +5 -1
  49. data/lib/mongo_mapper/query.rb +53 -120
  50. data/lib/mongo_mapper/support.rb +2 -213
  51. data/lib/mongo_mapper/support/descendant_appends.rb +3 -6
  52. data/lib/mongo_mapper/version.rb +2 -1
  53. metadata +156 -190
  54. data/.gitignore +0 -10
  55. data/Rakefile +0 -37
  56. data/mongo_mapper.gemspec +0 -216
  57. data/performance/read_write.rb +0 -52
  58. data/specs.watchr +0 -51
  59. data/test/NOTE_ON_TESTING +0 -1
  60. data/test/active_model_lint_test.rb +0 -13
  61. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +0 -63
  62. data/test/functional/associations/test_belongs_to_proxy.rb +0 -101
  63. data/test/functional/associations/test_in_array_proxy.rb +0 -325
  64. data/test/functional/associations/test_many_documents_as_proxy.rb +0 -229
  65. data/test/functional/associations/test_many_documents_proxy.rb +0 -536
  66. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +0 -176
  67. data/test/functional/associations/test_many_embedded_proxy.rb +0 -256
  68. data/test/functional/associations/test_many_polymorphic_proxy.rb +0 -302
  69. data/test/functional/associations/test_one_embedded_proxy.rb +0 -68
  70. data/test/functional/associations/test_one_proxy.rb +0 -196
  71. data/test/functional/test_associations.rb +0 -44
  72. data/test/functional/test_binary.rb +0 -27
  73. data/test/functional/test_callbacks.rb +0 -151
  74. data/test/functional/test_dirty.rb +0 -163
  75. data/test/functional/test_document.rb +0 -1219
  76. data/test/functional/test_embedded_document.rb +0 -210
  77. data/test/functional/test_identity_map.rb +0 -507
  78. data/test/functional/test_indexing.rb +0 -44
  79. data/test/functional/test_logger.rb +0 -20
  80. data/test/functional/test_modifiers.rb +0 -416
  81. data/test/functional/test_pagination.rb +0 -93
  82. data/test/functional/test_protected.rb +0 -163
  83. data/test/functional/test_string_id_compatibility.rb +0 -67
  84. data/test/functional/test_timestamps.rb +0 -64
  85. data/test/functional/test_userstamps.rb +0 -28
  86. data/test/functional/test_validations.rb +0 -342
  87. data/test/models.rb +0 -227
  88. data/test/support/custom_matchers.rb +0 -37
  89. data/test/support/timing.rb +0 -16
  90. data/test/test_helper.rb +0 -64
  91. data/test/unit/associations/test_base.rb +0 -212
  92. data/test/unit/associations/test_proxy.rb +0 -105
  93. data/test/unit/serializers/test_json_serializer.rb +0 -202
  94. data/test/unit/test_descendant_appends.rb +0 -71
  95. data/test/unit/test_document.rb +0 -225
  96. data/test/unit/test_dynamic_finder.rb +0 -123
  97. data/test/unit/test_embedded_document.rb +0 -657
  98. data/test/unit/test_keys.rb +0 -216
  99. data/test/unit/test_mongo_mapper.rb +0 -118
  100. data/test/unit/test_pagination.rb +0 -160
  101. data/test/unit/test_plugins.rb +0 -50
  102. data/test/unit/test_query.rb +0 -374
  103. data/test/unit/test_rails.rb +0 -181
  104. data/test/unit/test_rails_compatibility.rb +0 -52
  105. data/test/unit/test_serialization.rb +0 -51
  106. data/test/unit/test_support.rb +0 -390
  107. data/test/unit/test_time_zones.rb +0 -39
  108. data/test/unit/test_validations.rb +0 -544
@@ -1,10 +1,8 @@
1
- # Make sure you have the following libs in your load path or you could have issues:
2
- # gem 'activesupport', '>= 2.3.4'
3
- # gem 'mongo', '1.0'
4
- # gem 'jnunemaker-validatable', '1.8.4'
1
+ # encoding: UTF-8
2
+ # Make sure you have the correct versions of the gems (see gemspec) in your load path.
5
3
  require 'set'
6
4
  require 'uri'
7
- require 'mongo'
5
+ require 'plucky'
8
6
  require 'validatable'
9
7
  require 'active_support/all'
10
8
 
@@ -92,8 +90,7 @@ module MongoMapper
92
90
  end
93
91
 
94
92
  def self.setup(config, environment, options={})
95
- using_passenger = options.delete(:passenger)
96
- handle_passenger_forking if using_passenger
93
+ handle_passenger_forking
97
94
  self.config = config
98
95
  connect(environment, options)
99
96
  end
@@ -106,11 +103,12 @@ module MongoMapper
106
103
  end
107
104
  end
108
105
 
109
- autoload :Query, 'mongo_mapper/query'
110
106
  autoload :Document, 'mongo_mapper/document'
111
107
  autoload :EmbeddedDocument, 'mongo_mapper/embedded_document'
108
+ autoload :Query, 'mongo_mapper/query'
112
109
  autoload :Version, 'mongo_mapper/version'
113
110
  end
114
111
 
112
+ require 'mongo_mapper/extensions'
115
113
  require 'mongo_mapper/support'
116
114
  require 'mongo_mapper/plugins'
@@ -1,19 +1,21 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module Document
3
4
  extend Support::DescendantAppends
4
5
 
5
6
  def self.included(model)
6
7
  model.class_eval do
7
- include InstanceMethods
8
- extend Support::Find
9
- extend ClassMethods
10
8
  extend Plugins
11
9
 
10
+ plugin Plugins::Document
11
+ plugin Plugins::Querying # for now needs to be before associations (save_to_collection)
12
12
  plugin Plugins::Associations
13
13
  plugin Plugins::Clone
14
14
  plugin Plugins::Descendants
15
+ plugin Plugins::DynamicQuerying
15
16
  plugin Plugins::Equality
16
17
  plugin Plugins::Inspect
18
+ plugin Plugins::Indexes
17
19
  plugin Plugins::Keys
18
20
  plugin Plugins::Dirty # for now dirty needs to be after keys
19
21
  plugin Plugins::Logger
@@ -22,6 +24,7 @@ module MongoMapper
22
24
  plugin Plugins::Persistence
23
25
  plugin Plugins::Protected
24
26
  plugin Plugins::Rails
27
+ plugin Plugins::Sci
25
28
  plugin Plugins::Serialization
26
29
  plugin Plugins::Timestamps
27
30
  plugin Plugins::Userstamps
@@ -29,286 +32,8 @@ module MongoMapper
29
32
  plugin Plugins::Callbacks # for now callbacks needs to be after validations
30
33
  plugin Plugins::QueryLogger
31
34
 
32
- extend Plugins::Validations::DocumentMacros
33
35
  end
34
-
35
36
  super
36
37
  end
37
-
38
- module ClassMethods
39
- def inherited(subclass)
40
- subclass.set_collection_name(collection_name)
41
- super
42
- end
43
-
44
- def ensure_index(spec, options={})
45
- collection.create_index(spec, options)
46
- end
47
-
48
- def find(*args)
49
- assert_no_first_last_or_all(args)
50
- options = args.extract_options!
51
- return nil if args.size == 0
52
-
53
- if args.first.is_a?(Array) || args.size > 1
54
- find_some(args, options)
55
- else
56
- find_one(options.merge({:_id => args[0]}))
57
- end
58
- end
59
-
60
- def find!(*args)
61
- assert_no_first_last_or_all(args)
62
- options = args.extract_options!
63
- raise DocumentNotFound, "Couldn't find without an ID" if args.size == 0
64
-
65
- if args.first.is_a?(Array) || args.size > 1
66
- find_some!(args, options)
67
- else
68
- find_one(options.merge({:_id => args[0]})) || raise(DocumentNotFound, "Document match #{options.inspect} does not exist in #{collection.name} collection")
69
- end
70
- end
71
-
72
- def find_each(options={})
73
- criteria, options = to_query(options)
74
- collection.find(criteria, options).each do |doc|
75
- yield load(doc)
76
- end
77
- end
78
-
79
- def find_by_id(id)
80
- find(id)
81
- end
82
-
83
- def first_or_create(args)
84
- first(args) || create(args.reject { |key, value| !key?(key) })
85
- end
86
-
87
- def first_or_new(args)
88
- first(args) || new(args.reject { |key, value| !key?(key) })
89
- end
90
-
91
- def first(options={})
92
- find_one(options)
93
- end
94
-
95
- def last(options={})
96
- raise ':order option must be provided when using last' if options[:order].blank?
97
- find_one(options.merge(:order => invert_order_clause(options[:order])))
98
- end
99
-
100
- def all(options={})
101
- find_many(options)
102
- end
103
-
104
- def count(options={})
105
- collection.find(to_criteria(options)).count
106
- end
107
-
108
- def exists?(options={})
109
- !count(options).zero?
110
- end
111
-
112
- def create(*docs)
113
- initialize_each(*docs) { |doc| doc.save }
114
- end
115
-
116
- def create!(*docs)
117
- initialize_each(*docs) { |doc| doc.save! }
118
- end
119
-
120
- def update(*args)
121
- if args.length == 1
122
- update_multiple(args[0])
123
- else
124
- id, attributes = args
125
- update_single(id, attributes)
126
- end
127
- end
128
-
129
- def delete(*ids)
130
- collection.remove(to_criteria(:_id => ids.flatten))
131
- end
132
-
133
- def delete_all(options={})
134
- collection.remove(to_criteria(options))
135
- end
136
-
137
- def destroy(*ids)
138
- find_some!(ids.flatten).each(&:destroy)
139
- end
140
-
141
- def destroy_all(options={})
142
- find_each(options) { |document| document.destroy }
143
- end
144
-
145
- def embeddable?
146
- false
147
- end
148
-
149
- def single_collection_inherited?
150
- keys.key?(:_type) && single_collection_inherited_superclass?
151
- end
152
-
153
- def single_collection_inherited_superclass?
154
- superclass.respond_to?(:keys) && superclass.keys.key?(:_type)
155
- end
156
-
157
- private
158
- def initialize_each(*docs)
159
- instances = []
160
- docs = [{}] if docs.blank?
161
- docs.flatten.each do |attrs|
162
- doc = new(attrs)
163
- yield(doc)
164
- instances << doc
165
- end
166
- instances.size == 1 ? instances[0] : instances
167
- end
168
-
169
- def assert_no_first_last_or_all(args)
170
- if args[0] == :first || args[0] == :last || args[0] == :all
171
- raise ArgumentError, "#{self}.find(:#{args}) is no longer supported, use #{self}.#{args} instead."
172
- end
173
- end
174
-
175
- def find_some(ids, options={})
176
- ids = ids.flatten.compact.uniq
177
- find_many(options.merge(:_id => ids)).compact
178
- end
179
-
180
- def find_some!(ids, options={})
181
- ids = ids.flatten.compact.uniq
182
- documents = find_some(ids, options)
183
-
184
- if ids.size == documents.size
185
- documents
186
- else
187
- raise DocumentNotFound, "Couldn't find all of the ids (#{ids.to_sentence}). Found #{documents.size}, but was expecting #{ids.size}"
188
- end
189
- end
190
-
191
- # All query methods that load documents pass through find_one or find_many
192
- def find_one(options={})
193
- criteria, options = to_query(options)
194
- if doc = collection.find_one(criteria, options)
195
- load(doc)
196
- end
197
- end
198
-
199
- # All query methods that load documents pass through find_one or find_many
200
- def find_many(options)
201
- criteria, options = to_query(options)
202
- collection.find(criteria, options).to_a.map do |doc|
203
- load(doc)
204
- end
205
- end
206
-
207
- def invert_order_clause(order)
208
- order.split(',').map do |order_segment|
209
- if order_segment =~ /\sasc/i
210
- order_segment.sub /\sasc/i, ' desc'
211
- elsif order_segment =~ /\sdesc/i
212
- order_segment.sub /\sdesc/i, ' asc'
213
- else
214
- "#{order_segment.strip} desc"
215
- end
216
- end.join(',')
217
- end
218
-
219
- def update_single(id, attrs)
220
- if id.blank? || attrs.blank? || !attrs.is_a?(Hash)
221
- raise ArgumentError, "Updating a single document requires an id and a hash of attributes"
222
- end
223
-
224
- doc = find(id)
225
- doc.update_attributes(attrs)
226
- doc
227
- end
228
-
229
- def update_multiple(docs)
230
- unless docs.is_a?(Hash)
231
- raise ArgumentError, "Updating multiple documents takes 1 argument and it must be hash"
232
- end
233
-
234
- instances = []
235
- docs.each_pair { |id, attrs| instances << update(id, attrs) }
236
- instances
237
- end
238
-
239
- def to_criteria(options={})
240
- Query.new(self, options).criteria
241
- end
242
-
243
- def to_query(options={})
244
- Query.new(self, options).to_a
245
- end
246
- end
247
-
248
- module InstanceMethods
249
- def save(options={})
250
- options.assert_valid_keys(:validate, :safe)
251
- options.reverse_merge!(:validate => true)
252
- !options[:validate] || valid? ? create_or_update(options) : false
253
- end
254
-
255
- def save!(options={})
256
- options.assert_valid_keys(:safe)
257
- save(options) || raise(DocumentNotValid.new(self))
258
- end
259
-
260
- def destroy
261
- delete
262
- end
263
-
264
- def delete
265
- @_destroyed = true
266
- self.class.delete(id) unless new?
267
- end
268
-
269
- def new?
270
- @new
271
- end
272
-
273
- def destroyed?
274
- @_destroyed == true
275
- end
276
-
277
- def reload
278
- if attrs = collection.find_one({:_id => _id})
279
- self.class.associations.each { |name, assoc| send(name).reset if respond_to?(name) }
280
- self.attributes = attrs
281
- self
282
- else
283
- raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
284
- end
285
- end
286
-
287
- # Used by embedded docs to find root easily without if/respond_to? stuff.
288
- # Documents are always root documents.
289
- def _root_document
290
- self
291
- end
292
-
293
- private
294
- def create_or_update(options={})
295
- result = new? ? create(options) : update(options)
296
- result != false
297
- end
298
-
299
- def create(options={})
300
- save_to_collection(options)
301
- end
302
-
303
- def update(options={})
304
- save_to_collection(options)
305
- end
306
-
307
- def save_to_collection(options={})
308
- safe = options[:safe] || false
309
- @new = false
310
- collection.save(to_mongo, :safe => safe)
311
- end
312
- end
313
38
  end # Document
314
39
  end # MongoMapper
@@ -1,13 +1,13 @@
1
+ # encoding: UTF-8
1
2
  module MongoMapper
2
3
  module EmbeddedDocument
3
4
  extend Support::DescendantAppends
4
5
 
5
6
  def self.included(model)
6
7
  model.class_eval do
7
- include InstanceMethods
8
- extend ClassMethods
9
8
  extend Plugins
10
9
 
10
+ plugin Plugins::EmbeddedDocument
11
11
  plugin Plugins::Associations
12
12
  plugin Plugins::Clone
13
13
  plugin Plugins::Descendants
@@ -18,54 +18,14 @@ module MongoMapper
18
18
  plugin Plugins::Persistence
19
19
  plugin Plugins::Protected
20
20
  plugin Plugins::Rails
21
+ plugin Plugins::Sci
21
22
  plugin Plugins::Serialization
22
23
  plugin Plugins::Validations
23
24
  plugin Plugins::Callbacks
24
25
  plugin Plugins::QueryLogger
25
26
 
26
- attr_reader :_root_document, :_parent_document
27
27
  end
28
-
29
28
  super
30
29
  end
31
-
32
- module ClassMethods
33
- def embeddable?
34
- true
35
- end
36
-
37
- def embedded_in(owner_name)
38
- define_method(owner_name) { _parent_document }
39
- end
40
- end
41
-
42
- module InstanceMethods
43
- def destroyed?
44
- !!_root_document.try(:destroyed?)
45
- end
46
-
47
- def new?
48
- _root_document.try(:new?) || @new
49
- end
50
-
51
- def save(options={})
52
- if result = _root_document.try(:save, options)
53
- @new = false
54
- end
55
- result
56
- end
57
-
58
- def save!(options={})
59
- if result = _root_document.try(:save!, options)
60
- @new = false
61
- end
62
- result
63
- end
64
-
65
- def _parent_document=(value)
66
- @_root_document = value._root_document
67
- @_parent_document = value
68
- end
69
- end # InstanceMethods
70
- end # EmbeddedDocument
71
- end # MongoMapper
30
+ end
31
+ end
@@ -0,0 +1,190 @@
1
+ # encoding: UTF-8
2
+ class Array
3
+ def self.to_mongo(value)
4
+ value = value.respond_to?(:lines) ? value.lines : value
5
+ value.to_a
6
+ end
7
+
8
+ def self.from_mongo(value)
9
+ value || []
10
+ end
11
+ end
12
+
13
+ class Binary
14
+ def self.to_mongo(value)
15
+ if value.is_a?(BSON::Binary)
16
+ value
17
+ else
18
+ value.nil? ? nil : BSON::Binary.new(value)
19
+ end
20
+ end
21
+
22
+ def self.from_mongo(value)
23
+ value
24
+ end
25
+ end
26
+
27
+ class Boolean
28
+ BOOLEAN_MAPPING = {
29
+ true => true, 'true' => true, 'TRUE' => true, 'True' => true, 't' => true, 'T' => true, '1' => true, 1 => true, 1.0 => true,
30
+ false => false, 'false' => false, 'FALSE' => false, 'False' => false, 'f' => false, 'F' => false, '0' => false, 0 => false, 0.0 => false, nil => nil
31
+ }
32
+
33
+ def self.to_mongo(value)
34
+ if value.is_a?(Boolean)
35
+ value
36
+ else
37
+ BOOLEAN_MAPPING[value]
38
+ end
39
+ end
40
+
41
+ def self.from_mongo(value)
42
+ !!value
43
+ end
44
+ end
45
+
46
+ class Date
47
+ def self.to_mongo(value)
48
+ if value.nil? || value == ''
49
+ nil
50
+ else
51
+ date = value.is_a?(Date) || value.is_a?(Time) ? value : Date.parse(value.to_s)
52
+ Time.utc(date.year, date.month, date.day)
53
+ end
54
+ rescue
55
+ nil
56
+ end
57
+
58
+ def self.from_mongo(value)
59
+ value.to_date if value.present?
60
+ end
61
+ end
62
+
63
+ class Float
64
+ def self.to_mongo(value)
65
+ value.nil? ? nil : value.to_f
66
+ end
67
+ end
68
+
69
+ class Hash
70
+ def self.from_mongo(value)
71
+ HashWithIndifferentAccess.new(value || {})
72
+ end
73
+
74
+ def to_mongo
75
+ self
76
+ end
77
+ end
78
+
79
+ class Integer
80
+ def self.to_mongo(value)
81
+ value_to_i = value.to_i
82
+ if value_to_i == 0 && value != value_to_i
83
+ value.to_s =~ /^(0x|0b)?0+/ ? 0 : nil
84
+ else
85
+ value_to_i
86
+ end
87
+ end
88
+ end
89
+
90
+ class NilClass
91
+ def to_mongo(value)
92
+ value
93
+ end
94
+
95
+ def from_mongo(value)
96
+ value
97
+ end
98
+ end
99
+
100
+ class Object
101
+ # The hidden singleton lurks behind everyone
102
+ def metaclass
103
+ class << self; self end
104
+ end
105
+
106
+ def meta_eval(&blk)
107
+ metaclass.instance_eval(&blk)
108
+ end
109
+
110
+ # Adds methods to a metaclass
111
+ def meta_def(name, &blk)
112
+ meta_eval { define_method(name, &blk) }
113
+ end
114
+
115
+ # Defines an instance method within a class
116
+ def class_def(name, &blk)
117
+ class_eval { define_method(name, &blk) }
118
+ end
119
+
120
+ def self.to_mongo(value)
121
+ value
122
+ end
123
+
124
+ def self.from_mongo(value)
125
+ value
126
+ end
127
+ end
128
+
129
+ class ObjectId
130
+ def self.to_mongo(value)
131
+ Plucky.to_object_id(value)
132
+ end
133
+
134
+ def self.from_mongo(value)
135
+ value
136
+ end
137
+ end
138
+
139
+ class Set
140
+ def self.to_mongo(value)
141
+ value.to_a
142
+ end
143
+
144
+ def self.from_mongo(value)
145
+ Set.new(value || [])
146
+ end
147
+ end
148
+
149
+ class String
150
+ def self.to_mongo(value)
151
+ value.nil? ? nil : value.to_s
152
+ end
153
+
154
+ def self.from_mongo(value)
155
+ value.nil? ? nil : value.to_s
156
+ end
157
+ end
158
+
159
+ class Time
160
+ def self.to_mongo(value)
161
+ if value.nil? || value == ''
162
+ nil
163
+ else
164
+ time_class = Time.try(:zone).present? ? Time.zone : Time
165
+ time = value.is_a?(Time) ? value : time_class.parse(value.to_s)
166
+ # strip milliseconds as Ruby does micro and bson does milli and rounding rounded wrong
167
+ at(time.to_i).utc if time
168
+ end
169
+ end
170
+
171
+ def self.from_mongo(value)
172
+ if Time.try(:zone).present? && value.present?
173
+ value.in_time_zone(Time.zone)
174
+ else
175
+ value
176
+ end
177
+ end
178
+ end
179
+
180
+ class BSON::ObjectID
181
+ alias_method :original_to_json, :to_json
182
+
183
+ def as_json(options=nil)
184
+ to_s
185
+ end
186
+
187
+ def to_json(options = nil)
188
+ as_json.to_json
189
+ end
190
+ end