diff --git a/lib/schema/uuid.js b/lib/schema/uuid.js index aa72c42107..1fbfc38654 100644 --- a/lib/schema/uuid.js +++ b/lib/schema/uuid.js @@ -26,19 +26,6 @@ function hex2buffer(hex) { return buff; } -/** - * Helper function to convert the buffer input to a string - * @param {Buffer} buf The buffer to convert to a hex-string - * @returns {String} The buffer as a hex-string - * @api private - */ - -function binary2hex(buf) { - // use buffer built-in function to convert from buffer to hex-string - const hex = buf != null && buf.toString('hex'); - return hex; -} - /** * Convert a String to Binary * @param {String} uuidStr The value to process @@ -67,7 +54,7 @@ function binaryToString(uuidBin) { // i(hasezoey) dont quite know why, but "uuidBin" may sometimes also be the already processed string let hex; if (typeof uuidBin !== 'string' && uuidBin != null) { - hex = binary2hex(uuidBin); + hex = uuidBin.toString('hex'); const uuidStr = hex.substring(0, 8) + '-' + hex.substring(8, 8 + 4) + '-' + hex.substring(12, 12 + 4) + '-' + hex.substring(16, 16 + 4) + '-' + hex.substring(20, 20 + 12); return uuidStr; } @@ -90,7 +77,15 @@ function SchemaUUID(key, options) { if (value != null && value.$__ != null) { return value; } - return binaryToString(value); + if (Buffer.isBuffer(value)) { + return binaryToString(value); + } else if (value instanceof Binary) { + return binaryToString(value.buffer); + } else if (utils.isPOJO(value) && value.type === 'Buffer' && Array.isArray(value.data)) { + // Cloned buffers look like `{ type: 'Buffer', data: [5, 224, ...] }` + return binaryToString(Buffer.from(value.data)); + } + return value; }); } diff --git a/test/model.populate.test.js b/test/model.populate.test.js index 7f0fe844eb..be7933882f 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -11131,4 +11131,41 @@ describe('model: populate:', function() { } assert.equal(posts.length, 2); }); + + it('handles converting uuid documents to strings when calling toObject() (gh-14869)', async function() { + const nodeSchema = new Schema({ _id: { type: 'UUID' }, name: 'String' }); + const rootSchema = new Schema({ + _id: { type: 'UUID' }, + status: 'String', + node: [{ type: 'UUID', ref: 'Child' }] + }); + + const Node = db.model('Child', nodeSchema); + const Root = db.model('Parent', rootSchema); + + const node = new Node({ + _id: '65c7953e-c6e9-4c2f-8328-fe2de7df560d', + name: 'test' + }); + await node.save(); + + const root = new Root({ + _id: '05c7953e-c6e9-4c2f-8328-fe2de7df560d', + status: 'ok', + node: [node._id] + }); + await root.save(); + + const foundRoot = await Root.findById(root._id).populate('node'); + + let doc = foundRoot.toJSON({ getters: true }); + assert.strictEqual(doc._id, '05c7953e-c6e9-4c2f-8328-fe2de7df560d'); + assert.strictEqual(doc.node.length, 1); + assert.strictEqual(doc.node[0]._id, '65c7953e-c6e9-4c2f-8328-fe2de7df560d'); + + doc = foundRoot.toObject({ getters: true }); + assert.strictEqual(doc._id, '05c7953e-c6e9-4c2f-8328-fe2de7df560d'); + assert.strictEqual(doc.node.length, 1); + assert.strictEqual(doc.node[0]._id, '65c7953e-c6e9-4c2f-8328-fe2de7df560d'); + }); });