diff --git a/app/models/data_store_models.py b/app/models/data_store_models.py index 71215f1..2cf361f 100644 --- a/app/models/data_store_models.py +++ b/app/models/data_store_models.py @@ -106,6 +106,10 @@ class Data_Store_Base(BaseModel): values[f'{field}_random'] = resolved_rid # 3. Handle Polymorphic for_id + # v_data_store intentionally has no for_id_random JOIN column because for_type is + # runtime-variable (event, event_session, person, journal, etc.) — the target table + # is unknown at view-definition time. Resolution falls back to get_id_random() here. + # If resolution fails, Step 4 strips the raw integer to None — integers never leak. if f_rid := values.get('for_id_random'): values['for_id'] = f_rid elif values.get('for_id') and values.get('for_type'): diff --git a/documentation/BOOTSTRAP__AI_Agent_Quickstart.md b/documentation/BOOTSTRAP__AI_Agent_Quickstart.md index 0912952..f7a2e0f 100644 --- a/documentation/BOOTSTRAP__AI_Agent_Quickstart.md +++ b/documentation/BOOTSTRAP__AI_Agent_Quickstart.md @@ -261,6 +261,14 @@ Fix: add a mapping to the special-case block in `sanitize_payload()` (same file, if obj_type_lookup == 'poc_person': obj_type_lookup = 'person' ``` +#### Polymorphic FK fields (`for_id` / `for_type`) + +`data_store.for_id` is a polymorphic FK — `for_type` can be `event`, `event_session`, `person`, `journal`, or any other Aether object type, chosen at runtime. Because the target table is unknown at view-definition time, `v_data_store` intentionally **has no `for_id_random` JOIN column** (unlike `account_id_random`, which is a fixed JOIN to `account`). + +Resolution happens in the `Data_Store_Base.map_v3_ids` root validator (Step 3): it calls `get_id_random(for_id_int, for_type)` which does `SELECT id_random FROM {for_type} WHERE id = :id`, with Redis caching. If resolution fails, Step 4 strips the raw integer to `None` — **integers never appear in API responses**. + +> If you see `for_id: null` in a response where a value is expected, check that `for_type` matches a valid Aether table name and the referenced record exists. + #### Alt-view fields (in `tbl_alt` only) Some objects have a richer alternate SQL view triggered by `?view=alt`. These fields **must still be declared in the Pydantic model and `searchable_fields`** even if they only