Skip to main content

repository

Cache-backed implementation of the patient-data API's data-access seam.

Provides CacheBackedPatientDataRepository, which serves the API from the pod's background cache tables. The PatientDataRepository Protocol it implements lives in protocol.py.

Module

Functions

build_evidence_mapping

def build_evidence_mapping(evidence: Mapping[str, Any])> dict[str, str]:

Map criteria-matching config input fields to their evidence criterion key.

Rebuilt from the evidence itself: each criterion in evidence["criteria"] carries the config input field(s) that produced it (config_fields, a {config_field: {operator: operand}} map stamped at evidence-build time), so this inverts its keys to {config_field: output_field} without consulting any static config→criterion table. Lets a caller resolve "which evidence entry relates to total_ga_area_lower_bound?" directly. A range criterion's lower + upper bound both resolve to the one merged criterion.

Arguments

  • evidence: A patient_eligibility evidence object (with a criteria sub-map keyed by output_field), or any mapping carrying criteria.

Returns A {config_field: output_field} map over the criteria present. Empty for evidence lacking config_fields (e.g. rows written before it was added).

Classes

CacheBackedPatientDataRepository

class CacheBackedPatientDataRepository(    cache_getter: Callable[[], CacheProtocol],    image_service: ScanImageService | None = None,):

PatientDataRepository backed by the pod background cache.

Resolves each project_id to its authoritative partitions via the trials_published_data_pointer pointer, so every trial's data comes from a single published run and partitions are never mixed. The lookup is always paired with the table being read (_published_partitions): each step writes under its own Merkle hash, so there is no one hash that serves every table.

Arguments

  • cache_getter: A zero-arg callable returning the pod background cache. Called lazily and memoised on first use.
  • image_service: The scan-image renderer this repository dispatches to once a scan reference is resolved. None (the default) leaves the scan-image feature disabled, so get_scan_image reports it as not found rather than calling a method on None.

Methods


get_eligibility_counts

def get_eligibility_counts(    self, trial_ids: list[str],)> dict[str, EligibilityCounts]:

Return per-trial status counts, zeroed for unknown trials.

Arguments

  • trial_ids: The trial (project) IDs to count.

Returns A map of trial ID → EligibilityCounts.

get_eligibility_evidence

def get_eligibility_evidence(    self, bitfount_patient_id: str, project_id: str,)> EligibilityEvidence | None:

Return rolled-up evidence for a (patient, trial), or None.

Arguments

  • bitfount_patient_id: The Bitfount patient ID.
  • project_id: The trial (project) ID.

Returns The EligibilityEvidence, or None if there is no rollup.

get_patient

def get_patient(    self, bitfount_patient_id: str,)> PatientSummary | None:

Return a single patient summary, or None.

Resolves the identity row and eligible-trial set with targeted primary-key lookups rather than materialising every patient.

Arguments

  • bitfount_patient_id: The Bitfount patient ID.

Returns The PatientSummary, or None if the patient is unknown.

get_scan_image

def get_scan_image(    self,    *,    scan_id: str | None,    path: str | None,    modality: str | None,    laterality: str | None,    width: int | None,    refresh: bool,    include_masks: bool = False,    include_vectors: bool = False,    segmentation_classes: list[str] | None = None,)> bytes:

Resolve the scan reference and dispatch to the image service.

Arguments

  • scan_id: The scan identifier, or None (exactly one of scan_id/path).
  • path: An explicit, allowlisted file path, or None.
  • modality: Optional series selector for multi-series files.
  • laterality: Optional "L"/"R" series selector.
  • width: Optional output width (px); None uses the configured default.
  • refresh: When True, bypass and overwrite any cached archive.
  • include_masks: Whether the archive should carry a rendered mask PNG per segmentation class; passed straight through to the image service.
  • include_vectors: Whether the served index should carry each class's raw drawable instances; also passed straight through.
  • segmentation_classes: Optional class-name filter, applied only when an overlay output was requested.

Returns The application/zip archive bytes.

Raises

  • ScanNotFoundError: The scan-image feature is not enabled, or the reference does not resolve to an authorised file.
  • ScanRequestError: Not exactly one of scan_id/path was supplied, or the width/file is invalid (raised by the image service).

list_patients

def list_patients(    self,    *,    search: str | None = None,    eligible_trials: list[str] | None = None,    page: int = 1,    page_size: int = 50,)> PatientList:

Return one page of patients, filtered and searched in the database.

Filtering, search and windowing run in SQL (name/ehr_patient_id are plaintext columns), so only the requested page is materialised. Each returned patient keeps its full eligible-trial set regardless of the eligible_trials filter.

Arguments

  • search: Case-insensitive substring matched against name or EHR id.
  • eligible_trials: If given, restrict to patients eligible for any of these trials (union); blank entries are ignored, and an all-unknown/all-blank filter yields an empty page.
  • page: 1-indexed page number.
  • page_size: Page size (number of items per page).

Returns A PatientList whose items are the requested page and whose total is the count of all matching patients before pagination.

resolve_scan_path

def resolve_scan_path(self, *, scan_id: str | None, path: str | None)> str | None:

Resolve a scan reference to a validated absolute file path.

Arguments

  • scan_id: The scan identifier to resolve, or None.
  • path: An explicit filesystem path to validate, or None.

Both branches resolve only against the published scan partitions, so a scan whose only rows belong to a superseded run is not reachable — the same scoping the eligibility reads use.

Returns The validated real path, or None if unknown/unauthorised.

Raises

  • ValueError: If not exactly one of scan_id/path is supplied.