Topics discussed:
- A Postgres implementation now saves a ViewDefinition as a FHIR resource and materialises it into a real database view you can then query. Building it surfaced a question the spec hadn't answered: when you expand a nested element that isn't there, does the row disappear or survive with nulls? Both have uses — an inner join doubles as a filter, so you don't repeat the condition, but FHIR is full of optional elements you'd rather see as null than lose the whole patient over.
- The leaning was inner join as the default for
forEach, and two distinct keywords rather than one keyword with a modifier — fewer fields, andforEachalready reads as inner to people. Nobody could name the other one.unroll,expand,flatten,forEachOuterwere all floated, none stuck, and the group settled for putting it to a vote on Zulip. The related distinction that makes arrays coherent:forEachexplicitly unrolls a row per item, while selectingaddress.citywithout one simply gives you an array of cities — different keywords, no conflict. - Three implementations were converging by very different routes, and that was taken as the real signal. Postgres translates
forEachinto lateral joins; BigQuery emits UNNEST expressions joined inline; Pathling explodes everything into a cross join with a generated ID per repeating element and then filters down, because in Spark you want to leave the optimiser a clear path back to the source columns. Same semantics, unrecognisably different SQL. - Views deliberately do not join. One resource in, zero or many rows out — the group explored joins at this layer, found they got complicated and hard to port very quickly, and punted. Joins belong in the analytics layer, on top of the flat views, using whatever the user already has. A second layer of view-on-view, DBT-style, was floated for later, along with the observation that a DBT community or a Tableau community could settle its own conventions on top without the spec mandating anything.
- An idea worth its own thread: compile CQL down into these views. Analyse a set of measures, notice that they only touch a small subset of FHIR, generate the flat views they need, then rewrite the CQL to point at the flattened columns and let SQL do the rest — no FHIR storage required, and the data could even come from a legacy schema. The point back from the CQL side: CQL is already model-agnostic — most CQL in the world targets QDM, not FHIR — so you could declare a model for the flattened schema and write CQL against it directly.