Repository navigation
fix: export records in batches to stay under V8's string limit - #28
Merged
Merged
Conversation
A large records export failed with "RangeError: Cannot create a string longer than 0x1fffffe8 characters", because response.json() reads the whole body into one string. - REDCapAPI.recordBatches(): an opt-in async generator. It exports the matching record IDs first, then one records() request per batch. - #call rethrows the string-length RangeError with a message that points to recordBatches(). - REDCapProject.populate() loads records through recordBatches and takes an optional batchSize. Offline mode reads a records-eav/ folder of batch files when records-eav.json is absent. Fixes #27 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #27
Problem
REDCapAPI#callparses every response withresponse.json(), which reads the whole body into one string first. V8 caps a string at0x1fffffe8characters, so a large records export fails withRangeError: Cannot create a string longer than 0x1fffffe8 characters.REDCapProject.populate()runs into the limit in two places: it exports every record in one request, and in offline mode it readsrecords-eav.jsonas a single string.Changes
REDCapAPI.recordBatches(options, { batchSize = 500, idField })is a new async generator. It first exports only the ID field, as flat rows, to list the matching records. That request keeps the caller's filters (filterLogic,events, …) but notfields,formsortype. Duplicate IDs from repeat instances are removed. It then callsrecords()with the caller's options once per batch.recordsis already passed, those IDs are batched as given and no ID export is made.idFielddefaults to the first metadata field.batchSizethat is not a positive integer throws aRangeError.#callnow rethrows the string-lengthRangeErrorwith a message that points torecordBatches(). The original error is kept ascause. The failed-request path in#postis unchanged, so this does not overlap with API errors discard the response body, making import failures undiagnosable #25.REDCapProject.populate({ batchSize })now always loads records throughrecordBatches. That adds one request for the IDs and one per batch. It passes the record ID field it already has from the metadata, so it doesn't fetch the metadata again.records-eav.jsonis missing,populate()reads every*.jsonin arecords-eav/folder in filename order, one batch per file.Following the issue's non-goals,
records()never batches on its own, and no streaming parser is added.Testing
node:httptest server. They cover:idFieldand a given onebatchSizetest/fixtures/project-split/, holds theproject-basicrecords split across two files. The new test checks that it loads exactly the same data asproject-basic.populate({ batchSize: 1 })through the API against a local fake server. It made one flat request for the IDs, then one EAV request per record, and the records matched the offline fixture.RangeErroris not unit-tested, because triggering it needs a response larger than 512 MB.npm run lintandnpm testpass (84 tests).🤖 Generated with Claude Code