-- Analytics-friendly view over query_logs. -- Flattens commonly-queried keys from the `timings` jsonb so ad-hoc SQL -- doesn't need to remember every json path. New keys can be added without -- breaking existing queries (json operator returns NULL for missing keys). CREATE OR REPLACE VIEW "query_log_insights" AS SELECT ql.id, ql.user_id, ql.vin, substring(ql.vin from 1 for 3) AS wmi, ql.brand_id, ql.source, ql.success, ql.response_time_ms, ql.error_message, ql.created_at, (ql.timings->>'result_kind') AS result_kind, (ql.timings->>'cache_source') AS cache_source, (ql.timings->>'candidate_pick') AS candidate_pick, (ql.timings->>'pcat')::int AS pcat_ms, (ql.timings->>'emex')::int AS emex_ms, (ql.timings->>'pl24')::int AS pl24_ms, (ql.timings->>'vin_api')::int AS vin_api_ms, (ql.timings->>'lock_wait')::int AS lock_wait_ms, (ql.timings->>'pcat_car_count')::int AS pcat_car_count, (ql.timings->>'emex_candidate_count')::int AS emex_candidate_count, (ql.timings->>'pl24_circuit_open')::bool AS pl24_circuit_open, (ql.timings ? 'pl24_skipped') AS pl24_skipped, (ql.timings ? 'aborted') AS aborted, (ql.timings->>'vin_api_used')::bool AS vin_api_used, ql.timings AS raw_meta FROM query_logs ql;