Skip to content

Commit e3f37ea

Browse files
committed
Fetch PRs for all repos in one query
1 parent 1d6494e commit e3f37ea

File tree

1 file changed

+78
-64
lines changed

1 file changed

+78
-64
lines changed

src/features/projects/data/GitHubRepositoryDataSource.ts

Lines changed: 78 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -117,99 +117,113 @@ export default class GitHubProjectDataSource
117117
});
118118
})
119119
.then(async (repositories) => {
120+
// Fetch PRs for all repositories in a single query
121+
const allPullRequests = await this.getOpenPullRequestsForRepositories(
122+
repositories.map((repo) => ({
123+
owner: repo.owner.login,
124+
name: repo.name,
125+
}))
126+
);
127+
120128
// Map from the internal model to the public model.
121-
return await Promise.all(
122-
repositories.map(async (repository) => {
123-
// Fetch PRs for this repository in a separate query
124-
const pullRequests = await this.getOpenPullRequestsForRepository({
125-
owner: repository.owner.login,
126-
name: repository.name,
127-
});
129+
return repositories.map((repository) => {
130+
const repoKey = `${repository.owner.login}/${repository.name}`;
131+
const pullRequests = allPullRequests.get(repoKey) || new Map();
128132

129-
const branches = repository.branches.edges.map((branch) => {
130-
const pr = pullRequests.get(branch.node.name);
133+
const branches = repository.branches.edges.map((branch) => {
134+
const pr = pullRequests.get(branch.node.name);
131135

136+
return {
137+
id: branch.node.target.oid,
138+
name: branch.node.name,
139+
baseRef: pr?.baseRefName,
140+
baseRefOid: pr?.baseRefOid,
141+
files: branch.node.target.tree.entries,
142+
};
143+
});
144+
145+
return {
146+
name: repository.name,
147+
owner: repository.owner.login,
148+
defaultBranchRef: {
149+
id: repository.defaultBranchRef.target.oid,
150+
name: repository.defaultBranchRef.name,
151+
},
152+
configYml: repository.configYml,
153+
configYaml: repository.configYaml,
154+
branches: branches,
155+
tags: repository.tags.edges.map((branch) => {
132156
return {
133157
id: branch.node.target.oid,
134158
name: branch.node.name,
135-
baseRef: pr?.baseRefName,
136-
baseRefOid: pr?.baseRefOid,
137159
files: branch.node.target.tree.entries,
138160
};
139-
});
140-
141-
return {
142-
name: repository.name,
143-
owner: repository.owner.login,
144-
defaultBranchRef: {
145-
id: repository.defaultBranchRef.target.oid,
146-
name: repository.defaultBranchRef.name,
147-
},
148-
configYml: repository.configYml,
149-
configYaml: repository.configYaml,
150-
branches: branches,
151-
tags: repository.tags.edges.map((branch) => {
152-
return {
153-
id: branch.node.target.oid,
154-
name: branch.node.name,
155-
files: branch.node.target.tree.entries,
156-
};
157-
}),
158-
};
159-
})
160-
);
161+
}),
162+
};
163+
});
161164
});
162165
}
163166

164-
private async getOpenPullRequestsForRepository(params: {
165-
owner: string;
166-
name: string;
167-
}): Promise<Map<string, GraphQLPullRequest>> {
168-
const { owner, name } = params;
169-
const request = {
170-
query: `
171-
query PullRequests($owner: String!, $name: String!, $cursor: String) {
172-
repository(owner: $owner, name: $name) {
173-
pullRequests(first: 100, states: [OPEN, MERGED], after: $cursor) {
167+
private async getOpenPullRequestsForRepositories(
168+
repositories: Array<{ owner: string; name: string }>
169+
): Promise<Map<string, Map<string, GraphQLPullRequest>>> {
170+
if (repositories.length === 0) {
171+
return new Map();
172+
}
173+
174+
// Build a query that fetches PRs for all repositories
175+
const repoQueries = repositories
176+
.map((repo, index) => {
177+
return `
178+
repo${index}: repository(owner: "${repo.owner}", name: "${repo.name}") {
179+
pullRequests(first: 100, states: [OPEN, MERGED]) {
174180
edges {
175181
node {
176182
headRefName
177183
baseRefName
178184
baseRefOid
179185
}
180186
}
181-
pageInfo {
182-
hasNextPage
183-
endCursor
184-
}
185187
}
186-
}
188+
}`;
189+
})
190+
.join("\n");
191+
192+
const request = {
193+
query: `
194+
query PullRequests {
195+
${repoQueries}
187196
}
188197
`,
189-
variables: { owner, name, cursor: undefined },
198+
variables: {},
190199
};
191200

192201
const response = await this.graphQlClient.graphql(request);
193-
const pullRequests = new Map<string, GraphQLPullRequest>();
202+
const allPullRequests = new Map<string, Map<string, GraphQLPullRequest>>();
194203

195-
if (!response.repository?.pullRequests?.edges) {
196-
return pullRequests;
197-
}
204+
repositories.forEach((repo, index) => {
205+
const repoKey = `${repo.owner}/${repo.name}`;
206+
const repoData = response[`repo${index}`];
207+
const pullRequests = new Map<string, GraphQLPullRequest>();
198208

199-
// Map PRs by their head branch name for quick lookup
200-
const pullRequestEdges =
201-
response.repository.pullRequests.edges as Edge<GraphQLPullRequest>[];
209+
if (repoData?.pullRequests?.edges) {
210+
const pullRequestEdges =
211+
repoData.pullRequests.edges as Edge<GraphQLPullRequest>[];
202212

203-
pullRequestEdges.forEach((edge) => {
204-
const pr = edge.node;
205-
pullRequests.set(pr.headRefName, {
206-
headRefName: pr.headRefName,
207-
baseRefName: pr.baseRefName,
208-
baseRefOid: pr.baseRefOid,
209-
});
213+
pullRequestEdges.forEach((edge) => {
214+
const pr = edge.node;
215+
pullRequests.set(pr.headRefName, {
216+
headRefName: pr.headRefName,
217+
baseRefName: pr.baseRefName,
218+
baseRefOid: pr.baseRefOid,
219+
});
220+
});
221+
}
222+
223+
allPullRequests.set(repoKey, pullRequests);
210224
});
211225

212-
return pullRequests;
226+
return allPullRequests;
213227
}
214228

215229
private async getRepositoriesForSearchQuery(params: {

0 commit comments

Comments
 (0)