pwnash-mongo_mapper 0.7.5 → 0.7.6

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.
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