diff --git a/vehicle-data-platform/apps/api/internal/platform/mysql_queries.go b/vehicle-data-platform/apps/api/internal/platform/mysql_queries.go index 387da106..e044a98f 100644 --- a/vehicle-data-platform/apps/api/internal/platform/mysql_queries.go +++ b/vehicle-data-platform/apps/api/internal/platform/mysql_queries.go @@ -411,15 +411,16 @@ func buildVehicleRealtimeSQL(query url.Values) SQLQuery { if len(having) > 0 { havingSQL = ` HAVING ` + strings.Join(having, " AND ") + ` ` } - populationSQL := `(` + - `SELECT b0.vin, COALESCE(MAX(NULLIF(b0.plate, '')), '') AS plate, ` + + populationRowsSQL := `SELECT b0.vin, COALESCE(MAX(NULLIF(b0.plate, '')), '') AS plate, ` + `COALESCE(MAX(NULLIF(b0.phone, '')), '') AS phone, COALESCE(MAX(NULLIF(b0.oem, '')), '') AS oem, 'bound' AS binding_status ` + - `FROM vehicle_identity_binding b0 WHERE b0.vin IS NOT NULL AND b0.vin <> '' GROUP BY b0.vin ` + - `UNION ALL ` + - `SELECT l0.vin, COALESCE(MAX(NULLIF(l0.plate, '')), '') AS plate, '' AS phone, '' AS oem, 'unbound' AS binding_status ` + - `FROM vehicle_realtime_location l0 LEFT JOIN vehicle_identity_binding b1 ON b1.vin = l0.vin ` + - `WHERE l0.vin IS NOT NULL AND l0.vin <> '' AND b1.vin IS NULL GROUP BY l0.vin` + - `) v` + `FROM vehicle_identity_binding b0 WHERE b0.vin IS NOT NULL AND b0.vin <> '' GROUP BY b0.vin` + if strings.TrimSpace(query.Get("serviceStatus")) == "identity_required" { + populationRowsSQL += ` UNION ALL ` + + `SELECT l0.vin, COALESCE(MAX(NULLIF(l0.plate, '')), '') AS plate, '' AS phone, '' AS oem, 'unbound' AS binding_status ` + + `FROM vehicle_realtime_location l0 LEFT JOIN vehicle_identity_binding b1 ON b1.vin = l0.vin ` + + `WHERE l0.vin IS NOT NULL AND l0.vin <> '' AND b1.vin IS NULL GROUP BY l0.vin` + } + populationSQL := `(` + populationRowsSQL + `) v` baseGroupSQL := `FROM ` + populationSQL + ` ` + `LEFT JOIN vehicle_realtime_location l ON l.vin = v.vin ` + `LEFT JOIN vehicle_realtime_snapshot s ON s.vin = v.vin AND s.protocol = l.protocol ` diff --git a/vehicle-data-platform/apps/api/internal/platform/query_builders_test.go b/vehicle-data-platform/apps/api/internal/platform/query_builders_test.go index 7dbbd8b3..20cb670b 100644 --- a/vehicle-data-platform/apps/api/internal/platform/query_builders_test.go +++ b/vehicle-data-platform/apps/api/internal/platform/query_builders_test.go @@ -304,6 +304,20 @@ func TestBuildVehicleRealtimeSQLFiltersVehiclesWithoutRealtimeLocation(t *testin if !strings.Contains(built.Text, "AS location_available") { t.Fatalf("realtime row must expose explicit location availability: %s", built.Text) } + if strings.Contains(built.Text, "SELECT l0.vin") || strings.Contains(built.CountText, "SELECT l0.vin") { + t.Fatalf("default monitor population must stay on authoritative bound vehicles: %s / %s", built.Text, built.CountText) + } +} + +func TestBuildVehicleRealtimeSQLCanStillAuditUnboundRealtimeIdentities(t *testing.T) { + built := buildVehicleRealtimeSQL(url.Values{"serviceStatus": {"identity_required"}, "limit": {"20"}}) + for _, text := range []string{built.Text, built.CountText} { + for _, want := range []string{"UNION ALL", "SELECT l0.vin", "b1.vin IS NULL", "v.binding_status = 'bound'"} { + if !strings.Contains(text, want) { + t.Fatalf("identity-required audit must explicitly add unbound realtime identities, missing %q: %s", want, text) + } + } + } } func TestBuildDailyMileageSQL(t *testing.T) {