11import { inspect , promisify } from 'util' ;
22import { isUint8Array } from 'util/types' ;
33
4- import { type Document , EJSON , type EJSONOptions , type ObjectId } from './bson' ;
4+ import {
5+ type Binary ,
6+ type BSONRegExp ,
7+ type BSONSymbol ,
8+ type Code ,
9+ type DBRef ,
10+ type Decimal128 ,
11+ type Document ,
12+ type Double ,
13+ EJSON ,
14+ type EJSONOptions ,
15+ type Int32 ,
16+ type Long ,
17+ type MaxKey ,
18+ type MinKey ,
19+ type ObjectId ,
20+ type Timestamp
21+ } from './bson' ;
522import type { CommandStartedEvent } from './cmap/command_monitoring_events' ;
623import type {
724 ConnectionCheckedInEvent ,
@@ -414,6 +431,20 @@ export interface LogConvertible extends Record<string, any> {
414431 toLog ( ) : Record < string , any > ;
415432}
416433
434+ type BSONObject =
435+ | BSONRegExp
436+ | BSONSymbol
437+ | Code
438+ | DBRef
439+ | Decimal128
440+ | Double
441+ | Int32
442+ | Long
443+ | MaxKey
444+ | MinKey
445+ | ObjectId
446+ | Timestamp
447+ | Binary ;
417448/** @internal */
418449export function stringifyWithMaxLen (
419450 value : any ,
@@ -427,22 +458,98 @@ export function stringifyWithMaxLen(
427458 if ( currentLength >= maxDocumentLength ) {
428459 return undefined ;
429460 }
461+ // Account for root document
462+ if ( key === '' ) {
463+ // Account for starting brace
464+ currentLength += 1 ;
465+ return value ;
466+ }
430467
468+ // +4 accounts for 2 quotation marks, colon and comma after value
431469 currentLength += key . length + 4 ;
432470
433471 if ( typeof value === 'string' ) {
434- currentLength += value . length ;
472+ // +2 accounts for quotes
473+ currentLength += value . length + 2 ;
435474 } else if ( typeof value === 'number' || typeof value === 'bigint' ) {
436- currentLength += 20 ;
475+ currentLength += String ( value ) . length ;
437476 } else if ( typeof value === 'boolean' ) {
438477 currentLength += value ? 4 : 5 ;
478+ } else if ( 'buffer' in value && isUint8Array ( value . buffer ) ) {
479+ // Handle binData
480+ currentLength += ( value . buffer . byteLength + value . buffer . byteLength * 0.5 ) | 0 ;
439481 } else if ( value != null && typeof value === 'object' && '_bsontype' in value ) {
440- if ( isUint8Array ( value . buffer ) ) {
441- currentLength += ( value . buffer . byteLength + value . buffer . byteLength * 0.5 ) | 0 ;
442- } else if ( value . _bsontype === 'Binary' ) {
443- currentLength += ( value . position + value . position * 0.3 ) | 0 ;
444- } else if ( value . _bsontype === 'Code' ) {
445- currentLength += value . code . length ;
482+ const v = value as BSONObject ;
483+ if ( v . _bsontype === 'Binary' ) {
484+ // This is an estimate based on the fact that the base64 is approximately 1.3x the length of
485+ // the actual binary sequence
486+ // Also accounting for stringified fields before the binary sequence and the fields after
487+ // the binary sequence
488+ currentLength += ( value . position + value . position * 0.3 + 22 + 17 ) | 0 ;
489+ } else if ( v . _bsontype === 'Code' ) {
490+ // '{"$code":"<code>"}' or '{"$code":"<code>","$scope":<scope>}'
491+ // TODO: Account for scope?
492+ if ( v . scope == null ) {
493+ currentLength += v . code . length + 10 + 2 ;
494+ } else {
495+ // Ignoring actual scope object
496+ currentLength += v . code . length + 10 + 11 ;
497+ }
498+ } else if ( v . _bsontype === 'Decimal128' ) {
499+ // TODO: Is this worth doing here?
500+ currentLength += value . toExtendedJSON ( ) . length ;
501+ } else if ( v . _bsontype === 'Double' ) {
502+ // Doesn't account for representing integers as <value>.0
503+ if ( 'value' in v && typeof v . value === 'number' ) currentLength += String ( v . value ) . length ;
504+ } else if ( v . _bsontype === 'Int32' ) {
505+ if ( 'value' in v && typeof v . value === 'number' ) currentLength += String ( v . value ) . length ;
506+ } else if ( v . _bsontype === 'Long' ) {
507+ if ( 'toString' in v && typeof v . toString === 'function' ) {
508+ currentLength += v . toString ( ) . length ;
509+ }
510+ } else if ( v . _bsontype === 'MaxKey' || v . _bsontype === 'MinKey' ) {
511+ // '{"$maxKey":1}' or '{"$minKey":1}'
512+ currentLength += 13 ;
513+ } else if ( v . _bsontype === 'ObjectId' ) {
514+ // '{"$oid":"XXXXXXXXXXXXXXXXXXXXXXXX"}'
515+ currentLength += 35 ;
516+ } else if (
517+ v . _bsontype === 'BSONRegExp' &&
518+ 'pattern' in v &&
519+ typeof v . pattern === 'string' &&
520+ 'options' in v &&
521+ typeof v . options === 'string'
522+ ) {
523+ // '{"$regularExpression":{"pattern":"<pattern>","options":"<options>"}}'
524+ currentLength += 34 + v . pattern . length + 13 + v . options . length + 3 ;
525+ } else if ( v . _bsontype === 'BSONSymbol' && 'value' in v && v . value === 'string' ) {
526+ // '{"$symbol": "<value>"}'
527+ currentLength += 12 + v . value . length + 2 ;
528+ } else if (
529+ v . _bsontype === 'Timestamp' &&
530+ 't' in v &&
531+ typeof v . t === 'string' &&
532+ 'i' in v &&
533+ typeof v . i === 'string'
534+ ) {
535+ currentLength += 19 + String ( v . t ) . length + 5 + String ( v . i ) . length + 2 ;
536+ } else if ( v . _bsontype === 'DBRef' ) {
537+ // '{"$ref":"<collection>","$id":<stringified oid>}' or '{"$ref":"<collection>","$id":<stringified oid>,"$db":"test"}'
538+ currentLength += 9 ;
539+ // account for collection
540+ if ( 'collection' in v ) {
541+ currentLength += v . collection . length + 1 ;
542+ }
543+
544+ // account for db if present
545+ if ( 'db' in v && typeof v . db === 'string' ) {
546+ currentLength += 8 + v . db . length + 2 ;
547+ }
548+
549+ // account for oid if present
550+ if ( 'oid' in v ) {
551+ currentLength += 35 ;
552+ }
446553 }
447554 }
448555
0 commit comments