diff --git a/src/binary.ts b/src/binary.ts index 56106324..baabcef7 100644 --- a/src/binary.ts +++ b/src/binary.ts @@ -255,6 +255,16 @@ export class Binary { } return new Binary(data, type); } + + /** @internal */ + [Symbol.for('nodejs.util.inspect.custom')](): string { + return this.inspect(); + } + + inspect(): string { + const asBuffer = this.value(true); + return `Binary("${asBuffer.toString('hex')}", ${this.sub_type})`; + } } Object.defineProperty(Binary.prototype, '_bsontype', { value: 'Binary' }); diff --git a/src/code.ts b/src/code.ts index 66308dc0..e2bd2a65 100644 --- a/src/code.ts +++ b/src/code.ts @@ -42,6 +42,16 @@ export class Code { static fromExtendedJSON(doc: CodeExtended): Code { return new Code(doc.$code, doc.$scope); } + + /** @internal */ + [Symbol.for('nodejs.util.inspect.custom')](): string { + return this.inspect(); + } + + inspect(): string { + const codeJson = this.toJSON(); + return `Code("${codeJson.code}"${codeJson.scope ? `, ${JSON.stringify(codeJson.scope)}` : ''})`; + } } Object.defineProperty(Code.prototype, '_bsontype', { value: 'Code' }); diff --git a/src/db_ref.ts b/src/db_ref.ts index a42702c7..cfc69d20 100644 --- a/src/db_ref.ts +++ b/src/db_ref.ts @@ -98,6 +98,18 @@ export class DBRef { delete copy.$db; return new DBRef(doc.$ref, doc.$id, doc.$db, copy); } + + /** @internal */ + [Symbol.for('nodejs.util.inspect.custom')](): string { + return this.inspect(); + } + + inspect(): string { + // NOTE: if OID is an ObjectId class it will just print the oid string. + const oid = + this.oid === undefined || this.oid.toString === undefined ? this.oid : this.oid.toString(); + return `DBRef("${this.namespace}", "${oid}"${this.db ? `, "${this.db}"` : ''})`; + } } Object.defineProperty(DBRef.prototype, '_bsontype', { value: 'DBRef' }); diff --git a/src/decimal128.ts b/src/decimal128.ts index e2731a6b..4ed3605e 100644 --- a/src/decimal128.ts +++ b/src/decimal128.ts @@ -787,6 +787,15 @@ export class Decimal128 { static fromExtendedJSON(doc: Decimal128Extended): Decimal128 { return Decimal128.fromString(doc.$numberDecimal); } + + /** @internal */ + [Symbol.for('nodejs.util.inspect.custom')](): string { + return this.inspect(); + } + + inspect(): string { + return `Decimal128("${this.toString()}")`; + } } Object.defineProperty(Decimal128.prototype, '_bsontype', { value: 'Decimal128' }); diff --git a/src/double.ts b/src/double.ts index 933e4eea..862778f7 100644 --- a/src/double.ts +++ b/src/double.ts @@ -70,6 +70,16 @@ export class Double { const doubleValue = parseFloat(doc.$numberDouble); return options && options.relaxed ? doubleValue : new Double(doubleValue); } + + /** @internal */ + [Symbol.for('nodejs.util.inspect.custom')](): string { + return this.inspect(); + } + + inspect(): string { + const eJSON = this.toExtendedJSON() as DoubleExtended; + return `Double(${eJSON.$numberDouble})`; + } } Object.defineProperty(Double.prototype, '_bsontype', { value: 'Double' }); diff --git a/src/int_32.ts b/src/int_32.ts index 31daa5c0..b8c1f86c 100644 --- a/src/int_32.ts +++ b/src/int_32.ts @@ -50,6 +50,15 @@ export class Int32 { static fromExtendedJSON(doc: Int32Extended, options?: EJSONOptions): number | Int32 { return options && options.relaxed ? parseInt(doc.$numberInt, 10) : new Int32(doc.$numberInt); } + + /** @internal */ + [Symbol.for('nodejs.util.inspect.custom')](): string { + return this.inspect(); + } + + inspect(): string { + return `Int32(${this.valueOf()})`; + } } Object.defineProperty(Int32.prototype, '_bsontype', { value: 'Int32' }); diff --git a/src/long.ts b/src/long.ts index c445baca..2aae861c 100644 --- a/src/long.ts +++ b/src/long.ts @@ -943,6 +943,15 @@ export class Long { const result = Long.fromString(doc.$numberLong); return options && options.relaxed ? result.toNumber() : result; } + + /** @internal */ + [Symbol.for('nodejs.util.inspect.custom')](): string { + return this.inspect(); + } + + inspect(): string { + return `Long("${this.toString()}")`; + } } Object.defineProperty(Long.prototype, '__isLong__', { value: true }); diff --git a/src/max_key.ts b/src/max_key.ts index 8558bd25..5f8379a5 100644 --- a/src/max_key.ts +++ b/src/max_key.ts @@ -19,6 +19,15 @@ export class MaxKey { static fromExtendedJSON(): MaxKey { return new MaxKey(); } + + /** @internal */ + [Symbol.for('nodejs.util.inspect.custom')](): string { + return this.inspect(); + } + + inspect(): string { + return 'MaxKey()'; + } } Object.defineProperty(MaxKey.prototype, '_bsontype', { value: 'MaxKey' }); diff --git a/src/min_key.ts b/src/min_key.ts index 6506ebf4..ce2012a8 100644 --- a/src/min_key.ts +++ b/src/min_key.ts @@ -19,6 +19,15 @@ export class MinKey { static fromExtendedJSON(): MinKey { return new MinKey(); } + + /** @internal */ + [Symbol.for('nodejs.util.inspect.custom')](): string { + return this.inspect(); + } + + inspect(): string { + return 'MinKey()'; + } } Object.defineProperty(MinKey.prototype, '_bsontype', { value: 'MinKey' }); diff --git a/src/symbol.ts b/src/symbol.ts index 476cefee..6f82f0b3 100644 --- a/src/symbol.ts +++ b/src/symbol.ts @@ -30,7 +30,7 @@ export class BSONSymbol { /** @internal */ inspect(): string { - return this.value; + return `BSONSymbol("${this.value}")`; } /** @internal */ @@ -47,6 +47,11 @@ export class BSONSymbol { static fromExtendedJSON(doc: BSONSymbolExtended): BSONSymbol { return new BSONSymbol(doc.$symbol); } + + /** @internal */ + [Symbol.for('nodejs.util.inspect.custom')](): string { + return this.inspect(); + } } Object.defineProperty(BSONSymbol.prototype, '_bsontype', { value: 'Symbol' }); diff --git a/src/timestamp.ts b/src/timestamp.ts index cd9b9ba6..a0e9cf51 100644 --- a/src/timestamp.ts +++ b/src/timestamp.ts @@ -1,7 +1,7 @@ import { Long } from './long'; /** @public */ -export type TimestampOverrides = '_bsontype' | 'toExtendedJSON' | 'fromExtendedJSON'; +export type TimestampOverrides = '_bsontype' | 'toExtendedJSON' | 'fromExtendedJSON' | 'inspect'; /** @public */ export type LongWithoutOverrides = new (low: number | Long, high?: number, unsigned?: boolean) => { [P in Exclude]: Long[P]; @@ -91,4 +91,13 @@ export class Timestamp extends LongWithoutOverridesClass { static fromExtendedJSON(doc: TimestampExtended): Timestamp { return new Timestamp(doc.$timestamp.i, doc.$timestamp.t); } + + /** @internal */ + [Symbol.for('nodejs.util.inspect.custom')](): string { + return this.inspect(); + } + + inspect(): string { + return `Timestamp(${this.getLowBits().toString()}, ${this.getHighBits().toString()})`; + } } diff --git a/test/node/bson_test.js b/test/node/bson_test.js index 0dc4134d..fb5c95ca 100644 --- a/test/node/bson_test.js +++ b/test/node/bson_test.js @@ -18,6 +18,7 @@ const MaxKey = BSON.MaxKey; const { BinaryParser } = require('../binary_parser'); const vm = require('vm'); const { assertBuffersEqual } = require('./tools/utils'); +const { inspect } = require('util'); /** * Module for parsing an ISO 8601 formatted string into a Date object. @@ -2268,4 +2269,97 @@ describe('BSON', function () { expect(() => BSON.serialize(badArray)).to.throw(); expect(() => BSON.serialize(badMap)).to.throw(); }); + + describe('Should support util.inspect for', function () { + /** + * @ignore + */ + it('Binary', function () { + const binary = new Binary(Buffer.from('0123456789abcdef0123456789abcdef', 'hex'), 4); + expect(inspect(binary)).to.equal('Binary("0123456789abcdef0123456789abcdef", 4)'); + }); + + /** + * @ignore + */ + it('BSONSymbol', function () { + const symbol = new BSONSymbol('sym'); + expect(inspect(symbol)).to.equal('BSONSymbol("sym")'); + }); + + /** + * @ignore + */ + it('Code', function () { + const code = new Code('this.a > i', { i: 1 }); + expect(inspect(code)).to.equal('Code("this.a > i", {"i":1})'); + }); + + /** + * @ignore + */ + it('DBRef', function () { + const oid = new ObjectId('deadbeefdeadbeefdeadbeef'); + const dbref = new DBRef('namespace', oid, 'integration_tests_'); + expect(inspect(dbref)).to.equal( + 'DBRef("namespace", "deadbeefdeadbeefdeadbeef", "integration_tests_")' + ); + }); + + /** + * @ignore + */ + it('Decimal128', function () { + const dec = Decimal128.fromString('1.42'); + expect(inspect(dec)).to.equal('Decimal128("1.42")'); + }); + + /** + * @ignore + */ + it('Double', function () { + const double = new Double(-42.42); + expect(inspect(double)).to.equal('Double(-42.42)'); + }); + + /** + * @ignore + */ + it('Int32', function () { + const int = new Int32(42); + expect(inspect(int)).to.equal('Int32(42)'); + }); + + /** + * @ignore + */ + it('Long', function () { + const long = Long.fromString('42'); + expect(inspect(long)).to.equal('Long("42")'); + }); + + /** + * @ignore + */ + it('MaxKey', function () { + const maxKey = new MaxKey(); + expect(inspect(maxKey)).to.equal('MaxKey()'); + }); + + /** + * @ignore + */ + it('MinKey', function () { + const minKey = new MinKey(); + expect(inspect(minKey)).to.equal('MinKey()'); + }); + + /** + * @ignore + */ + it('Timestamp', function () { + const timestamp = new Timestamp(1, 100); + expect(inspect(timestamp)).to.equal('Timestamp(1, 100)'); + }); + }); });