From 21af5c6289b06221912758dda0ce92ca91c18078 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Wed, 6 Mar 2024 12:18:42 +0100 Subject: [PATCH 1/9] feat: show simpler uuid format VSCODE-470 --- src/editors/mongoDBDocumentService.ts | 50 ++++++++- .../editors/mongoDBDocumentService.test.ts | 106 +++++++++++++++++- 2 files changed, 153 insertions(+), 3 deletions(-) diff --git a/src/editors/mongoDBDocumentService.ts b/src/editors/mongoDBDocumentService.ts index 387a4d401..dddfb291d 100644 --- a/src/editors/mongoDBDocumentService.ts +++ b/src/editors/mongoDBDocumentService.ts @@ -93,7 +93,7 @@ export default class MongoDBDocumentService { await dataService.findOneAndReplace( namespace, { _id: documentId }, - newDocument, + this.extendEJSON(newDocument), { returnDocument: 'after', } @@ -108,6 +108,51 @@ export default class MongoDBDocumentService { } } + extendEJSON(document: Document): Document { + for (const [key, item] of Object.entries(document)) { + // UUIDs might be represented as {"$uuid": } in EJSON + // Binary subtypes 3 or 4 are used to represent UUIDs in BSON + // But, parsers MUST interpret the $uuid key as BSON Binary subtype 4 + // For this reason, we are applying this representation for subtype 4 only + // see https://github.com/mongodb/specifications/blob/master/source/extended-json.rst#special-rules-for-parsing-uuid-fields + if (item.hasOwnProperty('$uuid')) { + const base64 = Buffer.from( + item.$uuid.replaceAll('-', ''), + 'hex' + ).toString('base64'); + document[key] = { + $binary: { + base64, + subType: '04', + }, + }; + } + } + return document; + } + + simplifyEJSON(document: Document): Document { + for (const [key, item] of Object.entries(document)) { + // UUIDs might be represented as {"$uuid": } in EJSON + // Binary subtypes 3 or 4 are used to represent UUIDs in BSON + // But, parsers MUST interpret the $uuid key as BSON Binary subtype 4 + // For this reason, we are applying this representation for subtype 4 only + // see https://github.com/mongodb/specifications/blob/master/source/extended-json.rst#special-rules-for-parsing-uuid-fields + if (item.hasOwnProperty('$binary') && item.$binary.subType === '04') { + const hexString = Buffer.from(item.$binary.base64, 'base64').toString( + 'hex' + ); + const match = /^(.{8})(.{4})(.{4})(.{4})(.{12})$/.exec(hexString); + if (!match) continue; + const asUUID = match.slice(1, 6).join('-'); + document[key] = { + $uuid: asUUID, + }; + } + } + return document; + } + async fetchDocument(data: EditDocumentInfo): Promise { log.info('Fetch document from MongoDB', data); @@ -147,7 +192,8 @@ export default class MongoDBDocumentService { return; } - return JSON.parse(EJSON.stringify(documents[0])); + const ejson = JSON.parse(EJSON.stringify(documents[0])); + return this.simplifyEJSON(ejson); } catch (error) { this._statusView.hideMessage(); diff --git a/src/test/suite/editors/mongoDBDocumentService.test.ts b/src/test/suite/editors/mongoDBDocumentService.test.ts index f765d6b5b..5bea1f8c5 100644 --- a/src/test/suite/editors/mongoDBDocumentService.test.ts +++ b/src/test/suite/editors/mongoDBDocumentService.test.ts @@ -87,6 +87,57 @@ suite('MongoDB Document Service Test Suite', () => { expect(document).to.be.deep.equal(newDocument); }); + test('replaceDocument calls findOneAndReplace and saves a document when connected - extending the uuid type', async () => { + const namespace = 'waffle.house'; + const connectionId = 'tasty_sandwhich'; + const documentId = '93333a0d-83f6-4e6f-a575-af7ea6187a4a'; + const document: { _id: string; myUuid?: { $uuid: string } } = { + _id: '123', + }; + const newDocument = { + _id: '123', + myUuid: { + $binary: { + base64: 'yO2rw/c4TKO2jauSqRR4ow==', + subType: '04', + }, + }, + }; + const source = DocumentSource.DOCUMENT_SOURCE_TREEVIEW; + + const fakeActiveConnectionId = sandbox.fake.returns('tasty_sandwhich'); + sandbox.replace( + testConnectionController, + 'getActiveConnectionId', + fakeActiveConnectionId + ); + + const fakeGetActiveDataService = sandbox.fake.returns({ + findOneAndReplace: () => { + document.myUuid = { $uuid: 'c8edabc3-f738-4ca3-b68d-ab92a91478a3' }; + + return Promise.resolve(document); + }, + }); + sandbox.replace( + testConnectionController, + 'getActiveDataService', + fakeGetActiveDataService + ); + sandbox.stub(testStatusView, 'showMessage'); + sandbox.stub(testStatusView, 'hideMessage'); + + await testMongoDBDocumentService.replaceDocument({ + namespace, + documentId, + connectionId, + newDocument, + source, + }); + + expect(document).to.be.deep.equal(document); + }); + test('fetchDocument calls find and returns a single document when connected', async () => { const namespace = 'waffle.house'; const connectionId = 'tasty_sandwhich'; @@ -97,7 +148,7 @@ suite('MongoDB Document Service Test Suite', () => { const fakeGetActiveDataService = sandbox.fake.returns({ find: () => { - return Promise.resolve([{ _id: '123' }]); + return Promise.resolve(documents); }, }); sandbox.replace( @@ -127,6 +178,59 @@ suite('MongoDB Document Service Test Suite', () => { expect(result).to.be.deep.equal(JSON.parse(EJSON.stringify(documents[0]))); }); + test('fetchDocument simplifies the uuid type', async () => { + const namespace = 'waffle.house'; + const connectionId = 'tasty_sandwhich'; + const documentId = '93333a0d-83f6-4e6f-a575-af7ea6187a4a'; + const line = 1; + const documents = [ + { + _id: '123', + myUuid: { + $binary: { + base64: 'yO2rw/c4TKO2jauSqRR4ow==', + subType: '04', + }, + }, + }, + ]; + const source = DocumentSource.DOCUMENT_SOURCE_PLAYGROUND; + + const fakeGetActiveDataService = sandbox.fake.returns({ + find: () => { + return Promise.resolve(documents); + }, + }); + sandbox.replace( + testConnectionController, + 'getActiveDataService', + fakeGetActiveDataService + ); + + const fakeGetActiveConnectionId = sandbox.fake.returns(connectionId); + sandbox.replace( + testConnectionController, + 'getActiveConnectionId', + fakeGetActiveConnectionId + ); + + sandbox.stub(testStatusView, 'showMessage'); + sandbox.stub(testStatusView, 'hideMessage'); + + const result = await testMongoDBDocumentService.fetchDocument({ + namespace, + documentId, + line, + connectionId, + source, + }); + + expect(result).to.be.deep.equal({ + _id: '123', + myUuid: { $uuid: 'c8edabc3-f738-4ca3-b68d-ab92a91478a3' }, + }); + }); + test("if a user is not connected, documents won't be saved to MongoDB", async () => { const namespace = 'waffle.house'; const connectionId = 'tasty_sandwhich'; From 409dcfc6d0e18faa93152fe62e4e5aa1cdc80eda Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Wed, 6 Mar 2024 14:02:15 +0100 Subject: [PATCH 2/9] update comment and test name --- src/editors/mongoDBDocumentService.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/editors/mongoDBDocumentService.ts b/src/editors/mongoDBDocumentService.ts index dddfb291d..8a801004b 100644 --- a/src/editors/mongoDBDocumentService.ts +++ b/src/editors/mongoDBDocumentService.ts @@ -108,13 +108,9 @@ export default class MongoDBDocumentService { } } + // This is to revert the effects of simplifyEJSON extendEJSON(document: Document): Document { for (const [key, item] of Object.entries(document)) { - // UUIDs might be represented as {"$uuid": } in EJSON - // Binary subtypes 3 or 4 are used to represent UUIDs in BSON - // But, parsers MUST interpret the $uuid key as BSON Binary subtype 4 - // For this reason, we are applying this representation for subtype 4 only - // see https://github.com/mongodb/specifications/blob/master/source/extended-json.rst#special-rules-for-parsing-uuid-fields if (item.hasOwnProperty('$uuid')) { const base64 = Buffer.from( item.$uuid.replaceAll('-', ''), From c81909195c8676796d526457790fe1ef491373ff Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Wed, 6 Mar 2024 14:16:05 +0100 Subject: [PATCH 3/9] isObject --- src/editors/mongoDBDocumentService.ts | 11 +++++++++-- src/test/suite/editors/mongoDBDocumentService.test.ts | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/editors/mongoDBDocumentService.ts b/src/editors/mongoDBDocumentService.ts index 8a801004b..f096bfd66 100644 --- a/src/editors/mongoDBDocumentService.ts +++ b/src/editors/mongoDBDocumentService.ts @@ -18,6 +18,9 @@ export const DOCUMENT_SOURCE_URI_IDENTIFIER = 'source'; export const VIEW_DOCUMENT_SCHEME = 'VIEW_DOCUMENT_SCHEME'; +const isObject = (value: unknown) => + value !== null && typeof value === 'object' && !Array.isArray(value); + export default class MongoDBDocumentService { _context: vscode.ExtensionContext; _connectionController: ConnectionController; @@ -111,7 +114,7 @@ export default class MongoDBDocumentService { // This is to revert the effects of simplifyEJSON extendEJSON(document: Document): Document { for (const [key, item] of Object.entries(document)) { - if (item.hasOwnProperty('$uuid')) { + if (isObject(item) && item.hasOwnProperty('$uuid')) { const base64 = Buffer.from( item.$uuid.replaceAll('-', ''), 'hex' @@ -134,7 +137,11 @@ export default class MongoDBDocumentService { // But, parsers MUST interpret the $uuid key as BSON Binary subtype 4 // For this reason, we are applying this representation for subtype 4 only // see https://github.com/mongodb/specifications/blob/master/source/extended-json.rst#special-rules-for-parsing-uuid-fields - if (item.hasOwnProperty('$binary') && item.$binary.subType === '04') { + if ( + isObject(item) && + item.hasOwnProperty('$binary') && + item.$binary.subType === '04' + ) { const hexString = Buffer.from(item.$binary.base64, 'base64').toString( 'hex' ); diff --git a/src/test/suite/editors/mongoDBDocumentService.test.ts b/src/test/suite/editors/mongoDBDocumentService.test.ts index 5bea1f8c5..dea3477f5 100644 --- a/src/test/suite/editors/mongoDBDocumentService.test.ts +++ b/src/test/suite/editors/mongoDBDocumentService.test.ts @@ -178,7 +178,7 @@ suite('MongoDB Document Service Test Suite', () => { expect(result).to.be.deep.equal(JSON.parse(EJSON.stringify(documents[0]))); }); - test('fetchDocument simplifies the uuid type', async () => { + test('fetchDocument calls find and returns a single document when connected - simplifying the uuid type', async () => { const namespace = 'waffle.house'; const connectionId = 'tasty_sandwhich'; const documentId = '93333a0d-83f6-4e6f-a575-af7ea6187a4a'; From 188fd63ef1832b257fbdf20420814dbc182f2295 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Wed, 6 Mar 2024 14:41:03 +0100 Subject: [PATCH 4/9] remove reverse operation --- src/editors/mongoDBDocumentService.ts | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/editors/mongoDBDocumentService.ts b/src/editors/mongoDBDocumentService.ts index f096bfd66..b65ff0f14 100644 --- a/src/editors/mongoDBDocumentService.ts +++ b/src/editors/mongoDBDocumentService.ts @@ -96,7 +96,7 @@ export default class MongoDBDocumentService { await dataService.findOneAndReplace( namespace, { _id: documentId }, - this.extendEJSON(newDocument), + newDocument, { returnDocument: 'after', } @@ -111,25 +111,6 @@ export default class MongoDBDocumentService { } } - // This is to revert the effects of simplifyEJSON - extendEJSON(document: Document): Document { - for (const [key, item] of Object.entries(document)) { - if (isObject(item) && item.hasOwnProperty('$uuid')) { - const base64 = Buffer.from( - item.$uuid.replaceAll('-', ''), - 'hex' - ).toString('base64'); - document[key] = { - $binary: { - base64, - subType: '04', - }, - }; - } - } - return document; - } - simplifyEJSON(document: Document): Document { for (const [key, item] of Object.entries(document)) { // UUIDs might be represented as {"$uuid": } in EJSON From affd57ee5afe1caad5dfe58573681723ecc58544 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Wed, 6 Mar 2024 14:43:43 +0100 Subject: [PATCH 5/9] private notation --- src/editors/mongoDBDocumentService.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/editors/mongoDBDocumentService.ts b/src/editors/mongoDBDocumentService.ts index b65ff0f14..77c2fb23d 100644 --- a/src/editors/mongoDBDocumentService.ts +++ b/src/editors/mongoDBDocumentService.ts @@ -111,7 +111,7 @@ export default class MongoDBDocumentService { } } - simplifyEJSON(document: Document): Document { + _simplifyEJSON(document: Document): Document { for (const [key, item] of Object.entries(document)) { // UUIDs might be represented as {"$uuid": } in EJSON // Binary subtypes 3 or 4 are used to represent UUIDs in BSON @@ -177,7 +177,7 @@ export default class MongoDBDocumentService { } const ejson = JSON.parse(EJSON.stringify(documents[0])); - return this.simplifyEJSON(ejson); + return this._simplifyEJSON(ejson); } catch (error) { this._statusView.hideMessage(); From 83ae3eb1924a6e5a17d172b9a07f47f81d48f367 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Wed, 6 Mar 2024 17:15:39 +0100 Subject: [PATCH 6/9] Update src/editors/mongoDBDocumentService.ts Co-authored-by: Anna Henningsen --- src/editors/mongoDBDocumentService.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/editors/mongoDBDocumentService.ts b/src/editors/mongoDBDocumentService.ts index 77c2fb23d..2be38219b 100644 --- a/src/editors/mongoDBDocumentService.ts +++ b/src/editors/mongoDBDocumentService.ts @@ -120,8 +120,9 @@ export default class MongoDBDocumentService { // see https://github.com/mongodb/specifications/blob/master/source/extended-json.rst#special-rules-for-parsing-uuid-fields if ( isObject(item) && - item.hasOwnProperty('$binary') && - item.$binary.subType === '04' + Object.prototype.hasOwnProperty.call(item, '$binary') && + item.$binary?.subType === '04' && + typeof item.$binary.base64 === 'string' ) { const hexString = Buffer.from(item.$binary.base64, 'base64').toString( 'hex' From 78cadf1617c1ee9109c672c141c0f7118b549299 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Thu, 7 Mar 2024 17:31:07 +0100 Subject: [PATCH 7/9] apply for playground results + nested uuids --- src/editors/mongoDBDocumentService.ts | 35 +--------- src/language/worker.ts | 6 +- src/test/suite/utils/ejson.test.ts | 98 +++++++++++++++++++++++++++ src/utils/ejson.ts | 46 +++++++++++++ 4 files changed, 149 insertions(+), 36 deletions(-) create mode 100644 src/test/suite/utils/ejson.test.ts create mode 100644 src/utils/ejson.ts diff --git a/src/editors/mongoDBDocumentService.ts b/src/editors/mongoDBDocumentService.ts index 2be38219b..928d02de0 100644 --- a/src/editors/mongoDBDocumentService.ts +++ b/src/editors/mongoDBDocumentService.ts @@ -1,5 +1,4 @@ import type * as vscode from 'vscode'; -import { EJSON } from 'bson'; import type { Document } from 'bson'; import type ConnectionController from '../connectionController'; @@ -9,6 +8,7 @@ import type { EditDocumentInfo } from '../types/editDocumentInfoType'; import formatError from '../utils/formatError'; import type { StatusView } from '../views'; import type TelemetryService from '../telemetry/telemetryService'; +import { getEJSON } from '../utils/ejson'; const log = createLogger('document controller'); @@ -18,9 +18,6 @@ export const DOCUMENT_SOURCE_URI_IDENTIFIER = 'source'; export const VIEW_DOCUMENT_SCHEME = 'VIEW_DOCUMENT_SCHEME'; -const isObject = (value: unknown) => - value !== null && typeof value === 'object' && !Array.isArray(value); - export default class MongoDBDocumentService { _context: vscode.ExtensionContext; _connectionController: ConnectionController; @@ -111,33 +108,6 @@ export default class MongoDBDocumentService { } } - _simplifyEJSON(document: Document): Document { - for (const [key, item] of Object.entries(document)) { - // UUIDs might be represented as {"$uuid": } in EJSON - // Binary subtypes 3 or 4 are used to represent UUIDs in BSON - // But, parsers MUST interpret the $uuid key as BSON Binary subtype 4 - // For this reason, we are applying this representation for subtype 4 only - // see https://github.com/mongodb/specifications/blob/master/source/extended-json.rst#special-rules-for-parsing-uuid-fields - if ( - isObject(item) && - Object.prototype.hasOwnProperty.call(item, '$binary') && - item.$binary?.subType === '04' && - typeof item.$binary.base64 === 'string' - ) { - const hexString = Buffer.from(item.$binary.base64, 'base64').toString( - 'hex' - ); - const match = /^(.{8})(.{4})(.{4})(.{4})(.{12})$/.exec(hexString); - if (!match) continue; - const asUUID = match.slice(1, 6).join('-'); - document[key] = { - $uuid: asUUID, - }; - } - } - return document; - } - async fetchDocument(data: EditDocumentInfo): Promise { log.info('Fetch document from MongoDB', data); @@ -177,8 +147,7 @@ export default class MongoDBDocumentService { return; } - const ejson = JSON.parse(EJSON.stringify(documents[0])); - return this._simplifyEJSON(ejson); + return getEJSON(documents[0]); } catch (error) { this._statusView.hideMessage(); diff --git a/src/language/worker.ts b/src/language/worker.ts index c1c73854a..f0f7ba819 100644 --- a/src/language/worker.ts +++ b/src/language/worker.ts @@ -1,5 +1,4 @@ import { CliServiceProvider } from '@mongosh/service-provider-server'; -import { EJSON } from 'bson'; import { ElectronRuntime } from '@mongosh/browser-runtime-electron'; import { parentPort } from 'worker_threads'; import { ServerCommands } from './serverCommands'; @@ -10,6 +9,7 @@ import type { MongoClientOptions, } from '../types/playgroundType'; import util from 'util'; +import { getEJSON } from '../utils/ejson'; interface EvaluationResult { printable: any; @@ -18,12 +18,12 @@ interface EvaluationResult { const getContent = ({ type, printable }: EvaluationResult) => { if (type === 'Cursor' || type === 'AggregationCursor') { - return JSON.parse(EJSON.stringify(printable.documents)); + return getEJSON(printable.documents); } return typeof printable !== 'object' || printable === null ? printable - : JSON.parse(EJSON.stringify(printable)); + : getEJSON(printable); }; const getLanguage = (evaluationResult: EvaluationResult) => { diff --git a/src/test/suite/utils/ejson.test.ts b/src/test/suite/utils/ejson.test.ts new file mode 100644 index 000000000..f36198442 --- /dev/null +++ b/src/test/suite/utils/ejson.test.ts @@ -0,0 +1,98 @@ +import { expect } from 'chai'; +import { getEJSON } from '../../../utils/ejson'; + +suite('getEJSON', function () { + suite('Valid uuid', function () { + const prettyUuid = { + $uuid: '63b985b8-e8dd-4bda-9087-e4402f1a3ff5', + }; + const rawUuid = { + $binary: { + base64: 'Y7mFuOjdS9qQh+RALxo/9Q==', + subType: '04', + }, + }; + + test('Simplifies top-level uuid', function () { + const ejson = getEJSON({ uuid: rawUuid }); + expect(ejson).to.deep.equal({ uuid: prettyUuid }); + }); + + test('Simplifies nested uuid', function () { + const ejson = getEJSON({ + grandparent: { + parent: { + sibling: 1, + uuid: rawUuid, + }, + }, + }); + expect(ejson).to.deep.equal({ + grandparent: { + parent: { + sibling: 1, + uuid: prettyUuid, + }, + }, + }); + }); + + test('Simplifies uuid in a nested array', function () { + const ejson = getEJSON({ + items: [ + { + parent: { + sibling: 1, + uuid: rawUuid, + }, + }, + ], + }); + expect(ejson).to.deep.equal({ + items: [ + { + parent: { + sibling: 1, + uuid: prettyUuid, + }, + }, + ], + }); + }); + }); + + suite('Invalid uuid or not an uuid', function () { + test('Ignores another subtype', function () { + const document = { + $binary: { + base64: 'Y7mFuOjdS9qQh+RALxo/9Q==', + subType: '02', + }, + }; + const ejson = getEJSON(document); + expect(ejson).to.deep.equal(document); + }); + + test('Ignores invalid uuid', function () { + const document = { + $binary: { + base64: 'Y7m==', + subType: '04', + }, + }; + const ejson = getEJSON(document); + expect(ejson).to.deep.equal(document); + }); + + test('Ignores null', function () { + const document = { + $binary: { + base64: null, + subType: '04', + }, + }; + const ejson = getEJSON(document); + expect(ejson).to.deep.equal(document); + }); + }); +}); diff --git a/src/utils/ejson.ts b/src/utils/ejson.ts new file mode 100644 index 000000000..f62c02e05 --- /dev/null +++ b/src/utils/ejson.ts @@ -0,0 +1,46 @@ +import { EJSON } from 'bson'; +import type { Document } from 'bson'; + +const isObject = (value: unknown) => + value !== null && typeof value === 'object'; + +function simplifyEJSON(documents: Document[] | Document): Document { + if (!isObject(documents)) return documents; + + if (Array.isArray(documents)) { + return documents.map((item) => + isObject(item) ? simplifyEJSON(item) : item + ); + } + + // UUIDs might be represented as {"$uuid": } in EJSON + // Binary subtypes 3 or 4 are used to represent UUIDs in BSON + // But, parsers MUST interpret the $uuid key as BSON Binary subtype 4 + // For this reason, we are applying this representation for subtype 4 only + // see https://github.com/mongodb/specifications/blob/master/source/extended-json.rst#special-rules-for-parsing-uuid-fields + if ( + Object.prototype.hasOwnProperty.call(documents, '$binary') && + documents.$binary?.subType === '04' && + typeof documents.$binary.base64 === 'string' + ) { + const hexString = Buffer.from(documents.$binary.base64, 'base64').toString( + 'hex' + ); + const match = /^(.{8})(.{4})(.{4})(.{4})(.{12})$/.exec(hexString); + if (!match) return documents; + const asUUID = match.slice(1, 6).join('-'); + return { $uuid: asUUID }; + } + + return Object.fromEntries( + Object.entries(documents).map(([key, value]) => [ + key, + isObject(value) ? simplifyEJSON(value) : value, + ]) + ); +} + +export function getEJSON(documents: Document[] | Document) { + const ejson = JSON.parse(EJSON.stringify(documents)); + return simplifyEJSON(ejson); +} From 730165a6d8077244b99bf678c290a909bcacf082 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Mon, 11 Mar 2024 17:44:11 +0100 Subject: [PATCH 8/9] rename --- src/utils/ejson.ts | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/utils/ejson.ts b/src/utils/ejson.ts index f62c02e05..ffaef98c5 100644 --- a/src/utils/ejson.ts +++ b/src/utils/ejson.ts @@ -1,15 +1,15 @@ import { EJSON } from 'bson'; import type { Document } from 'bson'; -const isObject = (value: unknown) => +const isObjectOrArray = (value: unknown) => value !== null && typeof value === 'object'; -function simplifyEJSON(documents: Document[] | Document): Document { - if (!isObject(documents)) return documents; +function simplifyEJSON(item: Document[] | Document): Document { + if (!isObjectOrArray(item)) return item; - if (Array.isArray(documents)) { - return documents.map((item) => - isObject(item) ? simplifyEJSON(item) : item + if (Array.isArray(item)) { + return item.map((arrayItem) => + isObjectOrArray(arrayItem) ? simplifyEJSON(arrayItem) : arrayItem ); } @@ -19,28 +19,27 @@ function simplifyEJSON(documents: Document[] | Document): Document { // For this reason, we are applying this representation for subtype 4 only // see https://github.com/mongodb/specifications/blob/master/source/extended-json.rst#special-rules-for-parsing-uuid-fields if ( - Object.prototype.hasOwnProperty.call(documents, '$binary') && - documents.$binary?.subType === '04' && - typeof documents.$binary.base64 === 'string' + item.$binary?.subType === '04' && + typeof item.$binary?.base64 === 'string' ) { - const hexString = Buffer.from(documents.$binary.base64, 'base64').toString( + const hexString = Buffer.from(item.$binary.base64, 'base64').toString( 'hex' ); const match = /^(.{8})(.{4})(.{4})(.{4})(.{12})$/.exec(hexString); - if (!match) return documents; + if (!match) return item; const asUUID = match.slice(1, 6).join('-'); return { $uuid: asUUID }; } return Object.fromEntries( - Object.entries(documents).map(([key, value]) => [ + Object.entries(item).map(([key, value]) => [ key, - isObject(value) ? simplifyEJSON(value) : value, + isObjectOrArray(value) ? simplifyEJSON(value) : value, ]) ); } -export function getEJSON(documents: Document[] | Document) { - const ejson = JSON.parse(EJSON.stringify(documents)); +export function getEJSON(item: Document[] | Document) { + const ejson = JSON.parse(EJSON.stringify(item)); return simplifyEJSON(ejson); } From 6a1913e8ef3bf63c22dde21c8a1392eedffd5db1 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Mon, 11 Mar 2024 17:45:57 +0100 Subject: [PATCH 9/9] serialize --- src/test/suite/editors/mongoDBDocumentService.test.ts | 2 +- src/utils/ejson.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/suite/editors/mongoDBDocumentService.test.ts b/src/test/suite/editors/mongoDBDocumentService.test.ts index dea3477f5..dafbd5829 100644 --- a/src/test/suite/editors/mongoDBDocumentService.test.ts +++ b/src/test/suite/editors/mongoDBDocumentService.test.ts @@ -175,7 +175,7 @@ suite('MongoDB Document Service Test Suite', () => { source, }); - expect(result).to.be.deep.equal(JSON.parse(EJSON.stringify(documents[0]))); + expect(result).to.be.deep.equal(EJSON.serialize(documents[0])); }); test('fetchDocument calls find and returns a single document when connected - simplifying the uuid type', async () => { diff --git a/src/utils/ejson.ts b/src/utils/ejson.ts index ffaef98c5..01b419d62 100644 --- a/src/utils/ejson.ts +++ b/src/utils/ejson.ts @@ -40,6 +40,6 @@ function simplifyEJSON(item: Document[] | Document): Document { } export function getEJSON(item: Document[] | Document) { - const ejson = JSON.parse(EJSON.stringify(item)); + const ejson = EJSON.serialize(item); return simplifyEJSON(ejson); }