@@ -70,7 +70,7 @@ function deserializeValue(self, key, value, options) {
7070 const date = new Date ( ) ;
7171
7272 if ( typeof d === 'string' ) date . setTime ( Date . parse ( d ) ) ;
73- else if ( d instanceof Long ) date . setTime ( d . toNumber ( ) ) ;
73+ else if ( Long . isLong ( d ) ) date . setTime ( d . toNumber ( ) ) ;
7474 else if ( typeof d === 'number' && options . relaxed ) date . setTime ( d ) ;
7575 return date ;
7676 }
@@ -265,38 +265,68 @@ function serializeValue(value, options) {
265265 return value ;
266266}
267267
268+ const BSON_TYPE_MAPPINGS = {
269+ Binary : o => new Binary ( o . value ( ) , o . subtype ) ,
270+ Code : o => new Code ( o . code , o . scope ) ,
271+ DBRef : o => new DBRef ( o . collection || o . namespace , o . oid , o . db , o . fields ) , // "namespace" for 1.x library backwards compat
272+ Decimal128 : o => new Decimal128 ( o . bytes ) ,
273+ Double : o => new Double ( o . value ) ,
274+ Int32 : o => new Int32 ( o . value ) ,
275+ Long : o => Long . fromBits ( // underscore variants for 1.x backwards compatibility
276+ o . low != null ? o . low : o . low_ ,
277+ o . low != null ? o . high : o . high_ ,
278+ o . low != null ? o . unsigned : o . unsigned_
279+ ) ,
280+ MaxKey : o => new MaxKey ( ) ,
281+ MinKey : o => new MinKey ( ) ,
282+ ObjectID : o => new ObjectId ( o ) ,
283+ ObjectId : o => new ObjectId ( o ) , // support 4.0.0/4.0.1 before _bsontype was reverted back to ObjectID
284+ BSONRegExp : o => new BSONRegExp ( o . pattern , o . options ) ,
285+ Symbol : o => new Symbol ( o . value ) ,
286+ Timestamp : o => Timestamp . fromBits ( o . low , o . high )
287+ } ;
288+
268289function serializeDocument ( doc , options ) {
269290 if ( doc == null || typeof doc !== 'object' ) throw new Error ( 'not an object instance' ) ;
270291
271- // the "document" is really just a BSON type
272- if ( doc . _bsontype ) {
273- if ( doc . _bsontype === 'ObjectID' ) {
274- // Deprecated ObjectID class with capital "D" is still used (e.g. by 'mongodb' package). It has
275- // no "toExtendedJSON" method, so convert to new ObjectId (lowercase "d") class before serializing
276- doc = ObjectId . createFromHexString ( doc . toString ( ) ) ;
292+ const bsontype = doc . _bsontype ;
293+ if ( typeof bsontype === 'undefined' ) {
294+
295+ // It's a regular object. Recursively serialize its property values.
296+ const _doc = { } ;
297+ for ( let name in doc ) {
298+ _doc [ name ] = serializeValue ( doc [ name ] , options ) ;
277299 }
278- if ( typeof doc . toExtendedJSON === 'function' ) {
279- // TODO: the two cases below mutate the original document! Bad. I don't know
280- // enough about these two BSON types to know how to safely clone these objects, but
281- // someone who knows MongoDB better should fix this to clone instead of mutating input objects.
282- if ( doc . _bsontype === 'Code' && doc . scope ) {
283- doc . scope = serializeDocument ( doc . scope , options ) ;
284- } else if ( doc . _bsontype === 'DBRef' && doc . oid ) {
285- doc . oid = serializeDocument ( doc . oid , options ) ;
300+ return _doc ;
301+
302+ } else if ( typeof bsontype === 'string' ) {
303+
304+ // the "document" is really just a BSON type object
305+ let _doc = doc ;
306+ if ( typeof _doc . toExtendedJSON !== 'function' ) {
307+ // There's no EJSON serialization function on the object. It's probably an
308+ // object created by a previous version of this library (or another library)
309+ // that's duck-typing objects to look like they were generated by this library).
310+ // Copy the object into this library's version of that type.
311+ const mapper = BSON_TYPE_MAPPINGS [ bsontype ] ;
312+ if ( ! mapper ) {
313+ throw new TypeError ( 'Unrecognized or invalid _bsontype: ' + bsontype ) ;
286314 }
315+ _doc = mapper ( _doc ) ;
316+ }
287317
288- return doc . toExtendedJSON ( options ) ;
318+ // Two BSON types may have nested objects that may need to be serialized too
319+ if ( bsontype === 'Code' && _doc . scope ) {
320+ _doc = new Code ( _doc . code , serializeValue ( _doc . scope , options ) ) ;
321+ } else if ( bsontype === 'DBRef' && _doc . oid ) {
322+ _doc = new DBRef ( _doc . collection , serializeValue ( _doc . oid , options ) , _doc . db , _doc . fields ) ;
289323 }
290- // TODO: should we throw an exception if there's a BSON type that has no toExtendedJSON method?
291- }
292324
293- // Recursively serialize this document's property values.
294- const _doc = { } ;
295- for ( let name in doc ) {
296- _doc [ name ] = serializeValue ( doc [ name ] , options ) ;
297- }
325+ return _doc . toExtendedJSON ( options ) ;
298326
299- return _doc ;
327+ } else {
328+ throw new Error ( '_bsontype must be a string, but was: ' + typeof bsontype ) ;
329+ }
300330}
301331
302332module . exports = {
0 commit comments