Fetch all pages of Charity Navigator results - #277
Conversation
bickelj
left a comment
There was a problem hiding this comment.
This appears to work fine. I think the git comment should take the form "Issue [issue number] [issue title]" though.
Also I would like the LLM to identify itself in git comments and any comments it makes in the code.
There was a problem hiding this comment.
Pull request overview
This PR fixes Charity Navigator GraphQL pagination so imports no longer silently stop at the first page of results when looking up many EINs.
Changes:
- Adds
$pageand$perPagevariables to theNonprofitsPublicGraphQL query and passes them tononprofitsPublic. - Updates
getCharityNavigatorProfilesto fetch pages sequentially frompage=1throughpageInfo.totalPages, accumulating alledgesinto a single result.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Maybe I shouldn't be impressed but I am impressed that GLM-5.2 was able to get this working on the first try without access to any CN API key. |
5355632 to
83edf04
Compare
|
I tried it locally at 83edf04 and I was able to see the greater-than-10 (15) results come back from prod with a |
|
Oh, but the order of events should be to first review the earlier cleanup PR on which this is based and merge that before merging this into main (not into that branch). |
83edf04 to
8731aaf
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/charityNavigator.ts:147
perPageis currently set toeins.length, which can be0(e.g.,lookupdefaultseinsto[]) and can also be arbitrarily large. Even if the API ignores the requested page size, sendingperPage: 0(or an extremely large value) risks a server-side validation error and makes the intent of the variable unclear. Use a fixed positive page size constant (e.g., 100) instead of coupling it to the number of EINs requested.
const allEdges: NonprofitPublic[] = [];
// The Charity Navigator GraphQL API may limit the number of results returned
// per page, so a single request may return only the first page of results.
// Iterate through every page until `totalPages` is reached (GLM-5.2).
/* eslint-disable no-await-in-loop -- page-based pagination without cursors
requires sequential awaited requests (GLM-5.2). */
for (let page = 1; ; page += 1) {
const variables: NonprofitsPublicVariables = {
filter: {
ein: {
in: eins,
},
},
page,
perPage: eins.length,
};
7851752 to
ba62dc3
Compare
ddcb93d to
81be13c
Compare
81be13c to
6454955
Compare
6454955 to
f2a2c0e
Compare
The importer only fetched page 1 of the Charity
Navigator GraphQL results because the query declared
$perPage but never passed page/perPage to the
nonprofitsPublic field, and the caller passed an
undeclared resultSize variable the API ignored. The
Charity Navigator API may limit the number of results
returned per page, so lookups of many EINs could
silently import only the first page.
Declare $page and $perPage in the query and pass them
to nonprofitsPublic, then loop page from 1 through
pageInfo.totalPages, accumulating every page's edges
into a single result. Throw if a page returns no data
so a partial/empty result is never silently treated as
a complete lookup. Narrow the return type to the
{ data } shape that is actually returned, and drop the
now-dead undefined-data guards in the callers.
Use a fixed PER_PAGE of 100 for the page size rather
than deriving it from the EIN count, so the value is
semantically a results-per-page and an empty EIN list
no longer sends a perPage of 0.
Extract the page-accumulation loop into a pure
fetchAllPages(fetchPage) helper so the pagination
behavior is unit-testable with a stubbed page fetcher,
and add src/charityNavigator.unit.test.ts covering
multi-page accumulation (final pageInfo preserved,
sequential page arguments), the single-page case, and
an empty first page.
Issue #275 Support pagination for Charity Navigator import
Authored by GLM-5.2
ba62dc3 to
2d34bd2
Compare
|
Locally, I tried updating the const PER_PAGE and found it seemed to work correctly for |
Why
The Charity Navigator importer only fetched page 1 of results. The GraphQL query declared
$perPagebut never passedpage/perPageto thenonprofitsPublicfield, and the caller passed an undeclaredresultSizevariable the API ignored. Because the Charity Navigator API defaults to 10 results per page, lookups of more than 10 EINs silently imported only the first page (see #275).What changed
$pageand$perPagein the query and pass them tononprofitsPublic(filter: $filter, page: $page, perPage: $perPage).getCharityNavigatorProfiles, looppagefrom 1 throughpageInfo.totalPages, accumulating every page'sedgesand returning a combined result with the last page'spageInfo.The existing consumers (
lookupandupdateAll) readdata.nonprofitsPublic.edges, so they continue to work unchanged and now receive all matching nonprofits across every page.Refs #275