Skip to content

Commit c70c82d

Browse files
authoredMar 16, 2023
feat(NODE-4789): support Map stringification in EJSON (#567)
1 parent 24c6a9c commit c70c82d

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed
 

‎src/extended_json.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { Long } from './long';
1717
import { MaxKey } from './max_key';
1818
import { MinKey } from './min_key';
1919
import { ObjectId } from './objectid';
20-
import { isDate, isRegExp } from './parser/utils';
20+
import { isDate, isRegExp, isMap } from './parser/utils';
2121
import { BSONRegExp } from './regexp';
2222
import { BSONSymbol } from './symbol';
2323
import { Timestamp } from './timestamp';
@@ -190,6 +190,18 @@ function getISOString(date: Date) {
190190

191191
// eslint-disable-next-line @typescript-eslint/no-explicit-any
192192
function serializeValue(value: any, options: EJSONSerializeOptions): any {
193+
if (value instanceof Map || isMap(value)) {
194+
const obj: Record<string, unknown> = Object.create(null);
195+
for (const [k, v] of value) {
196+
if (typeof k !== 'string') {
197+
throw new BSONError('Can only serialize maps with string keys');
198+
}
199+
obj[k] = v;
200+
}
201+
202+
return serializeValue(obj, options);
203+
}
204+
193205
if ((typeof value === 'object' || typeof value === 'function') && value !== null) {
194206
const index = options.seenObjects.findIndex(entry => entry.obj === value);
195207
if (index !== -1) {

‎test/node/extended_json.test.ts

+39
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const EJSON = BSON.EJSON;
33
import * as vm from 'node:vm';
44
import { expect } from 'chai';
55
import { BSONVersionError, BSONRuntimeError } from '../../src';
6+
import { BSONError } from '../register-bson';
67

78
// BSON types
89
const Binary = BSON.Binary;
@@ -583,4 +584,42 @@ describe('Extended JSON', function () {
583584
})
584585
).to.throw(BSONVersionError, /Unsupported BSON version/i);
585586
});
587+
588+
context('Map objects', function () {
589+
it('serializes an empty Map object', () => {
590+
const input = new Map();
591+
expect(EJSON.stringify(input)).to.equal('{}');
592+
});
593+
594+
it('serializes a nested Map object', () => {
595+
const input = new Map([
596+
[
597+
'a',
598+
new Map([
599+
['a', 100],
600+
['b', 200]
601+
])
602+
]
603+
]);
604+
605+
const str = EJSON.stringify(input);
606+
expect(str).to.equal('{"a":{"a":100,"b":200}}');
607+
});
608+
609+
it('serializes a Map with one string key', () => {
610+
const input = new Map([['a', 100]]);
611+
612+
const str = EJSON.stringify(input);
613+
expect(str).to.equal('{"a":100}');
614+
});
615+
616+
it('throws BSONError when passed Map object with non-string keys', () => {
617+
const input: Map<number, unknown> = new Map([
618+
[1, 100],
619+
[2, 200]
620+
]);
621+
622+
expect(() => EJSON.stringify(input)).to.throw(BSONError);
623+
});
624+
});
586625
});

0 commit comments

Comments
 (0)
Please sign in to comment.