From e3e8d944b20231ab20ec96de1ed9ca156187ccf8 Mon Sep 17 00:00:00 2001 From: Jakob Ackermann Date: Fri, 16 May 2025 09:04:09 +0100 Subject: [PATCH] [web] fetch project members in a single db query (#25662) * [web] fetch project members in a single db query GitOrigin-RevId: ca749327d4783c67a3ad81f611cd7d3e7fa84028 --- .../Collaborators/CollaboratorsGetter.js | 58 +++++++++---------- .../Collaborators/CollaboratorsGetterTests.js | 37 +++++------- 2 files changed, 41 insertions(+), 54 deletions(-) diff --git a/services/web/app/src/Features/Collaborators/CollaboratorsGetter.js b/services/web/app/src/Features/Collaborators/CollaboratorsGetter.js index 77fb7ab2d3..caa6ef159d 100644 --- a/services/web/app/src/Features/Collaborators/CollaboratorsGetter.js +++ b/services/web/app/src/Features/Collaborators/CollaboratorsGetter.js @@ -385,34 +385,32 @@ function _getMemberIdsWithPrivilegeLevelsFromFields( } async function _loadMembers(members) { - const limit = pLimit(3) - const results = await Promise.all( - members.map(member => - limit(async () => { - const user = await UserGetter.promises.getUser(member.id, { - _id: 1, - email: 1, - features: 1, - first_name: 1, - last_name: 1, - signUpDate: 1, - }) - if (user != null) { - const record = { - user, - privilegeLevel: member.privilegeLevel, - } - if (member.pendingEditor) { - record.pendingEditor = true - } else if (member.pendingReviewer) { - record.pendingReviewer = true - } - return record - } else { - return null - } - }) - ) - ) - return results.filter(r => r != null) + const userIds = Array.from(new Set(members.map(m => m.id))) + const users = new Map() + for (const user of await UserGetter.promises.getUsers(userIds, { + _id: 1, + email: 1, + features: 1, + first_name: 1, + last_name: 1, + signUpDate: 1, + })) { + users.set(user._id.toString(), user) + } + return members + .map(member => { + const user = users.get(member.id) + if (!user) return null + const record = { + user, + privilegeLevel: member.privilegeLevel, + } + if (member.pendingEditor) { + record.pendingEditor = true + } else if (member.pendingReviewer) { + record.pendingReviewer = true + } + return record + }) + .filter(r => r != null) } diff --git a/services/web/test/unit/src/Collaborators/CollaboratorsGetterTests.js b/services/web/test/unit/src/Collaborators/CollaboratorsGetterTests.js index 7bfbc1c423..dda99e04f3 100644 --- a/services/web/test/unit/src/Collaborators/CollaboratorsGetterTests.js +++ b/services/web/test/unit/src/Collaborators/CollaboratorsGetterTests.js @@ -52,6 +52,7 @@ describe('CollaboratorsGetter', function () { this.UserGetter = { promises: { getUser: sinon.stub().resolves(null), + getUsers: sinon.stub().resolves([]), }, } this.ProjectMock = sinon.mock(Project) @@ -205,21 +206,13 @@ describe('CollaboratorsGetter', function () { describe('getInvitedMembersWithPrivilegeLevels', function () { beforeEach(function () { - this.UserGetter.promises.getUser - .withArgs(this.readOnlyRef1.toString()) - .resolves({ _id: this.readOnlyRef1 }) - this.UserGetter.promises.getUser - .withArgs(this.readOnlyTokenRef.toString()) - .resolves({ _id: this.readOnlyTokenRef }) - this.UserGetter.promises.getUser - .withArgs(this.readWriteRef2.toString()) - .resolves({ _id: this.readWriteRef2 }) - this.UserGetter.promises.getUser - .withArgs(this.readWriteTokenRef.toString()) - .resolves({ _id: this.readWriteTokenRef }) - this.UserGetter.promises.getUser - .withArgs(this.reviewer1Ref.toString()) - .resolves({ _id: this.reviewer1Ref }) + this.UserGetter.promises.getUsers.resolves([ + { _id: this.readOnlyRef1 }, + { _id: this.readOnlyTokenRef }, + { _id: this.readWriteRef2 }, + { _id: this.readWriteTokenRef }, + { _id: this.reviewer1Ref }, + ]) }) it('should return an array of invited members with their privilege levels', async function () { @@ -416,15 +409,11 @@ describe('CollaboratorsGetter', function () { { _id: this.reviewUser._id, email: this.reviewUser.email }, ], } - this.UserGetter.promises.getUser - .withArgs(this.owningUser._id.toString()) - .resolves(this.owningUser) - this.UserGetter.promises.getUser - .withArgs(this.readWriteUser._id.toString()) - .resolves(this.readWriteUser) - this.UserGetter.promises.getUser - .withArgs(this.reviewUser._id.toString()) - .resolves(this.reviewUser) + this.UserGetter.promises.getUsers.resolves([ + this.owningUser, + this.readWriteUser, + this.reviewUser, + ]) this.ProjectEditorHandler.buildOwnerAndMembersViews.returns(this.views) this.result = await this.CollaboratorsGetter.promises.getAllInvitedMembers(