Proof of concept (without tests) - #3
Open
david-mears-2 wants to merge 97 commits into
Open
Conversation
scripts/create_example_model_outputs.R writes three parquet files at data/model/2026.05.08/ (one per admin level 0–2) with real GADM region IDs for sub-Saharan Africa fetched from the grout endpoint, variant strings selected (by non-committed code) from WHO target markers, ene/mutation columns derived via variantstring, gapless monthly time series per variant (biased to later years), summary/exceedance value columns, and data support columns (no_of_informing_surveys, nearest_survey_by_time) using real survey IDs from stave_data.rds.
…egion id of most granular level
…ten and (2) not run out of memory when running
Create DuckDB instance in persistent mode so that we can use the READ_ONLY setting (not available in in-memory mode). Both persistent and in-memory mode use spilling to disk to facilitate larger-than-memory workloads (i.e., out-of-core-processing). https://duckdb.org/docs/current/clients/node_neo/overview\#create-instance 'dummy.db' will not be used, but it is required to pass in a db file name when creating an instance in persistent mode.
david-mears-2
force-pushed
the
poc-no-tests
branch
from
September 3, 2026 15:25
2b40089 to
9bc5186
Compare
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
There are verified correctness/config issues (e.g., properties parsing mismatch can generate invalid SQL, and package-lock/package.json dependency mismatch can break npm ci) that should be fixed before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR turns the repository into a functional proof-of-concept Express API that serves PARAmap survey/model data directly from Parquet via DuckDB, with supporting scripts and documentation for generating/fetching required data assets.
Changes:
- Adds read-only API endpoints (
/metadata,/surveys,/prevalences) with request validation and DuckDB-backed Parquet querying. - Introduces data/version discovery + setup scripts (STAVE processing tweaks, example model outputs generation, admin0 bounds fetch).
- Adjusts TypeScript/build configuration and project metadata (separate build tsconfig, new entrypoint, CI name/docs updates).
File summaries
| File | Description |
|---|---|
| tsconfig.json | Switches to repo-root rootDir, enables noEmit, includes scripts in typecheck. |
| tsconfig.build.json | Adds a dedicated build config that emits dist/ output. |
| src/utils/validators.ts | Adds request/query validation helpers (required params, releases, date rules, admin level). |
| src/utils/metadata.ts | Adds DuckDB query helper to compute gene/mutation metadata for /metadata. |
| src/utils/endpoints.ts | Defines endpoint configs and composes endpoint-specific validators. |
| src/utils/data.ts | Implements Parquet column inspection + SQL generation + prepared statement execution. |
| src/types.ts | Introduces shared types for query params and metadata payloads. |
| src/server.ts | Adds a dedicated runtime entrypoint that starts the Express app. |
| src/queryEngine.ts | Creates a DuckDB instance/connection configured for read-only access. |
| src/middlewares/errorHandler.ts | Tweaks error handler signature/linting. |
| src/constants.ts | Adds shared constants and discovers available model/data versions from the data directory. |
| src/config/config.ts | Extends config with dataDir/latestModelVersion and makes port optional at config level. |
| src/app.ts | Implements the main Express app and the three read-only endpoints. |
| scripts/process_stave.R | Adjusts STAVE preprocessing to rename/round lat/lng columns. |
| scripts/fetch_admin0_region_metadata.ts | Adds a setup script to fetch admin0 bounds metadata from Grout. |
| scripts/create_example_model_outputs.R | Adds script to generate example model output Parquet files for development. |
| README.md | Documents endpoints, examples, and local setup/data update workflow. |
| package.json | Updates build/start/dev scripts and adds DuckDB dependency. |
| package-lock.json | Updates lockfile for new dependencies/tooling. |
| data/model/2026.05.08/metadata.json | Adds an example model release metadata file linking to a data release. |
| .gitignore | Ignores generated data artifacts (region metadata + parquet files). |
| .github/workflows/ci.yml | Renames workflow display name to “CI”. |
Review details
Suppressed comments (2)
README.md:109
- This code block is labeled as JSON, but it contains a
// ...comment and trailing commas, which are invalid JSON. Consider switching the fence tojsoncso the example matches the syntax shown.
response:
```json
[
{
package.json:31
package-lock.jsonlistsvitest,supertest, and@types/supertestas top-level devDependencies, butpackage.jsondoes not. This mismatch typically causesnpm cito fail; alignpackage.jsonwith the lockfile (or regenerate the lockfile).
"devDependencies": {
"@eslint/js": "^10.0.1",
"@types/express": "^5.0.6",
"@types/node": "^24.0.0",
"eslint": "^10.8.0",
"nodemon": "^3.1.14",
"prettier": "^3.9.6",
"ts-node": "^10.9.2",
"typescript": "^6.0.3",
"typescript-eslint": "^8.65.0"
- Files reviewed: 19/23 changed files
- Comments generated: 8
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Don't validate a different thing than what is interpolated into SQL
Exclude non-date values like 2020-99-99 Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.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.
For a thorough description, please see the README.
Tests in #4
SQL injection prevention
There are three places SQL injection could theoretically be done: the list of columns to SELECT, the WHERE clause, and the interpolated parquet filename.
I followed the guidance here to guard the WHERE clause: https://duckdb.org/docs/lts/operations_manual/securing_duckdb/overview#prepared-statements-to-prevent-sql-injection.
The list of columns to SELECT is guarded by
validateRequestedPropertieswhich checks the properties against an allowlist configured per endpoint.The parquet filenames are guarded by validating that the inserted release name (e.g. 2026.05.08) is actually present as a sub-directory in the data directory: see
validateModelRelease,validateDataRelease.