Skip to content

fix(portal): resolve cache dataset cache_id to databaseCode - #3316

Open
SantanM wants to merge 3 commits into
developfrom
SantanM/revert-cache-dataset-catalog
Open

fix(portal): resolve cache dataset cache_id to databaseCode#3316
SantanM wants to merge 3 commits into
developfrom
SantanM/revert-cache-dataset-catalog

Conversation

@SantanM

@SantanM SantanM commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Problem

Creating a data mart has been broken since fc0eb12 (#3064). A newly created cache/data-mart
dataset was assigned cache_id = sanitizeIdForCacheId(snapshotId) — a per-dataset DuckDB
catalog name that nothing in the system ever creates or attaches in trex.

The datamart cache flow hardcodes use_trex_connection = True, connects to trex pgwire with
dbname = options.cache_id, and issues catalog-qualified DDL:

CREATE SCHEMA IF NOT EXISTS "<catalog>"."<schema>";

(create_cachedb_file_plugin/copy.py:62-97). Against an unattached catalog that fails:

Catalog Error: SET schema: No catalog + schema named "_959cfb54_3adb_48d0_b1e8_7b151d01e39c" found.

createDatasetSnapshot makes no trex /attach call — the only trexApiService.attach() call
site in the repo is in createDataset, for the source dataset — so the snapshot's catalog is
never attached, and the cache file for it is never written.

Root cause

resolveCacheId special-cased only dialect === 'hana' and type === 'source'. Every cache
dataset type fell through to the sanitized-id branch. CachedbController compounded it by
sourcing the cache-file write target from the cache dataset's own cache_id
(resolveCacheWriteTarget) instead of the source dataset's.

Before fc0eb12 the snapshot inherited the source row's cache_id, which
FixSourceDatasetCacheId1778417559069 had set to database_code — a real, always-attached
trex catalog. AddDatasetCacheId1778417559068 had likewise backfilled every pre-existing row
to database_code, which is why only data marts created after fc0eb12 are affected.

Fix

  1. resolveCacheId — added a CACHE_DATASET_TYPES branch (omop, study, non_omop,
    hana__omop, hana__non_omop) resolving to databaseCode. Scoping it to only omop
    would have left study and non_omop data marts broken — both are user-selectable
    (CopyStudyDialog, AddStudyDialog) and the /snapshot route triggers the cache flow with
    no type guard. The hana and source branches (Adding source type dataset should set databaseCode as cacheid #2877) are untouched.

    The fix is in the shared resolver rather than at the call site, so the value persisted to
    cache_id and the value handed to trex /attach still cannot drift.

  2. CachedbController — write target back to dataset.cacheId ?? databaseCode (the source
    row). Removed resolveCacheWriteTarget and its test; it had a single caller.

  3. Migration 1778417559070 — repairs data marts created since fc0eb12 by inheriting the
    source row's cache_id, matching what the code now computes. source_dataset_id is set only
    by createDatasetSnapshot, so it targets exactly the affected rows; the IS DISTINCT FROM
    guard skips rows already correct. Non-reversible by design, same as …069.

webapi, fhir and strategus_analysis datasets are deliberately excluded — they genuinely
own a per-dataset catalog. Confirmed on a live stack: each has its own .db file on disk and
appears in duckdb_databases().

Verification

Unit tests:

  • portal — 9 passed (39 steps), 0 failed
  • jobplugins — 21 passed, 0 failed

Mechanism, against a live trex:

USE "_959cfb54_3adb_48d0_b1e8_7b151d01e39c"   -> Catalog Error: No catalog + schema named ...
USE "demo_database"                            -> OK

Migration on a live DB — repaired exactly the one broken row, left webapi and
strategus_analysis untouched.

End-to-end, with the branch deployed:

Step Result
POST /gateway/api/dataset/snapshot 200, dataset a0150c51-…
Persisted cache_id demo_database (pre-fix: _a0150c51_e1ed_42b8_…)
Prefect flow run COMPLETED
Cache landed schema cdma0150c51… + 2 fts_* schemas in the demo_database catalog
Data copied person = 2,694 rows

Known gap, not addressed here

createDatasetSnapshot still makes no trex /attach call. That does not matter now that cache
datasets resolve to an always-attached catalog, but it is the reason fc0eb12's per-dataset
catalog design could not work. Anyone reintroducing per-cache-dataset catalogs must add the
attach step and have the flow wait for it.

santan maddi added 3 commits September 9, 2026 14:07
fc0eb12 gave data marts their own trex catalog, which nothing attaches,
so their cache flow run failed on the first task.
Drops resolveCacheWriteTarget; the per-snapshot catalog it returned is
never attached in trex.
Re-points data marts created since fc0eb12 at their source row's
attached trex catalog.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

FHIR and Strategus snapshots can persist a different catalog from the cache flow’s write target.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Fixes data-mart cache catalog resolution and repairs affected datasets.

Changes:

  • Resolves cache dataset IDs to source catalogs.
  • Updates cache-flow write targeting and tests.
  • Adds a corrective database migration.
File summaries
File Description
dataset.entity.ts Adds cache-type resolution rules.
dataset.entity.test.ts Tests the updated type matrix.
dataset-command.service.ts Updates snapshot cache assignment.
dataset-command.cache-id.test.ts Tests snapshot persistence.
1778417559070-fix-cache-dataset-cache-id.ts Repairs existing snapshot rows.
migration-data-source.ts Registers the migration.
cacheWriteTarget.ts Removes obsolete helper.
cacheWriteTarget.test.ts Removes helper tests.
CachedbController.ts Uses the source cache target.
Review details
  • Files reviewed: 9/9 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +59 to +60
if (dataset.type && CACHE_DATASET_TYPES.has(dataset.type)) {
return dataset.databaseCode ?? null
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants