diff --git a/go/vehicle-gateway/internal/history/query.go b/go/vehicle-gateway/internal/history/query.go index fe1038f1..e84de4ea 100644 --- a/go/vehicle-gateway/internal/history/query.go +++ b/go/vehicle-gateway/internal/history/query.go @@ -66,7 +66,6 @@ type LocationQuery struct { type LocationRow struct { TS string `json:"ts"` EventID string `json:"event_id"` - FrameID string `json:"frame_id"` ReceivedAt string `json:"received_at"` Longitude float64 `json:"longitude"` Latitude float64 `json:"latitude"` @@ -193,7 +192,6 @@ func (r *LocationRepository) Query(ctx context.Context, query LocationQuery) ([] if err := rows.Scan( &ts, &row.EventID, - &row.FrameID, &receivedAt, &row.Longitude, &row.Latitude, @@ -430,7 +428,7 @@ func quotedList(values []string) string { func buildLocationSQL(table string, query LocationQuery) (string, []any) { where := locationWhere(query) - sqlText := `SELECT ts, event_id, frame_id, received_at, longitude, latitude, altitude_m, speed_kmh, direction_deg, alarm_flag, status_flag, total_mileage_km, protocol, vin FROM ` + table + sqlText := `SELECT ts, event_id, received_at, longitude, latitude, altitude_m, speed_kmh, direction_deg, alarm_flag, status_flag, total_mileage_km, protocol, vin FROM ` + table if len(where) > 0 { sqlText += " WHERE " + strings.Join(where, " AND ") } diff --git a/go/vehicle-gateway/internal/history/query_test.go b/go/vehicle-gateway/internal/history/query_test.go index 01bcd7ea..8afd8776 100644 --- a/go/vehicle-gateway/internal/history/query_test.go +++ b/go/vehicle-gateway/internal/history/query_test.go @@ -306,10 +306,10 @@ func TestLocationHandlerReturnsLocationsByVIN(t *testing.T) { WillReturnRows(sqlmock.NewRows([]string{"total"}).AddRow(17)) mock.ExpectQuery("vin = 'LKLG7C4E3NA774736'"). WillReturnRows(sqlmock.NewRows([]string{ - "ts", "event_id", "frame_id", "received_at", "longitude", "latitude", "altitude_m", "speed_kmh", + "ts", "event_id", "received_at", "longitude", "latitude", "altitude_m", "speed_kmh", "direction_deg", "alarm_flag", "status_flag", "total_mileage_km", "protocol", "vin", }).AddRow( - "2026-07-02 00:18:22", "event-3", "go_frame", "2026-07-02 00:22:43", + "2026-07-02 00:18:22", "event-3", "2026-07-02 00:22:43", 121.07764, 30.585928, 11.0, 8.0, 171, 0, 4718595, 8792.8, "JT808", "LKLG7C4E3NA774736", )) @@ -329,7 +329,7 @@ func TestLocationHandlerReturnsLocationsByVIN(t *testing.T) { t.Fatalf("response missing %s: %s", want, body) } } - for _, legacy := range []string{"vehicle_key", "phone", "device_id"} { + for _, legacy := range []string{"frame_id", "vehicle_key", "phone", "device_id"} { if strings.Contains(body, legacy) { t.Fatalf("location response should not expose %s: %s", legacy, body) } @@ -347,10 +347,10 @@ func TestLocationHandlerSkipsTotalCountByDefault(t *testing.T) { defer db.Close() mock.ExpectQuery("vin = 'LKLG7C4E3NA774736'"). WillReturnRows(sqlmock.NewRows([]string{ - "ts", "event_id", "frame_id", "received_at", "longitude", "latitude", "altitude_m", "speed_kmh", + "ts", "event_id", "received_at", "longitude", "latitude", "altitude_m", "speed_kmh", "direction_deg", "alarm_flag", "status_flag", "total_mileage_km", "protocol", "vin", }).AddRow( - "2026-07-02 00:18:22", "event-3", "go_frame", "2026-07-02 00:22:43", + "2026-07-02 00:18:22", "event-3", "2026-07-02 00:22:43", 121.07764, 30.585928, 11.0, 8.0, 171, 0, 4718595, 8792.8, "JT808", "LKLG7C4E3NA774736", )) @@ -448,6 +448,9 @@ func TestBuildLocationSQLUsesLiteralsForTDengine(t *testing.T) { if strings.Contains(sqlText, "vehicle_key") || strings.Contains(sqlText, "phone") || strings.Contains(sqlText, "device_id") { t.Fatalf("location sql should use vin-only identity filters: %s", sqlText) } + if strings.Contains(sqlText, "frame_id") { + t.Fatalf("location sql should not select duplicate raw frame id: %s", sqlText) + } } func TestBuildRawFrameSQLUsesLiteralsForTDengine(t *testing.T) { diff --git a/go/vehicle-gateway/internal/history/schema.go b/go/vehicle-gateway/internal/history/schema.go index 6240f8c3..01a43d40 100644 --- a/go/vehicle-gateway/internal/history/schema.go +++ b/go/vehicle-gateway/internal/history/schema.go @@ -49,7 +49,6 @@ func SchemaStatements(database string) []string { `CREATE STABLE IF NOT EXISTS vehicle_locations ( ts TIMESTAMP, event_id NCHAR(64), - frame_id NCHAR(64), received_at TIMESTAMP, longitude DOUBLE, latitude DOUBLE, diff --git a/go/vehicle-gateway/internal/history/writer.go b/go/vehicle-gateway/internal/history/writer.go index b5583111..9279b0f7 100644 --- a/go/vehicle-gateway/internal/history/writer.go +++ b/go/vehicle-gateway/internal/history/writer.go @@ -113,7 +113,7 @@ func (w *Writer) AppendLocation(ctx context.Context, env envelope.FrameEnvelope) return err } _, err := w.exec.ExecContext(ctx, fmt.Sprintf(`INSERT INTO %s - (ts, event_id, frame_id, received_at, longitude, latitude, altitude_m, speed_kmh, + (ts, event_id, received_at, longitude, latitude, altitude_m, speed_kmh, direction_deg, alarm_flag, status_flag, total_mileage_km) VALUES (%s)`, table, joinLiterals(locationValues(env, longitude, latitude)))) return err @@ -249,7 +249,6 @@ func locationValues(env envelope.FrameEnvelope, longitude float64, latitude floa return []any{ eventTimeOrReceived(env), env.StableEventID(), - frameID(env), received, longitude, latitude, diff --git a/go/vehicle-gateway/internal/history/writer_test.go b/go/vehicle-gateway/internal/history/writer_test.go index f5caabfe..5f044928 100644 --- a/go/vehicle-gateway/internal/history/writer_test.go +++ b/go/vehicle-gateway/internal/history/writer_test.go @@ -23,9 +23,9 @@ func TestSchemaStatementsCreateCoreStables(t *testing.T) { t.Fatalf("raw schema should not create duplicate fields_json column:\n%s", statements) } locationStable := between(statements, "CREATE STABLE IF NOT EXISTS vehicle_locations", "}") - for _, field := range []string{"vehicle_key", "phone", "device_id"} { + for _, field := range []string{"frame_id", "vehicle_key", "phone", "device_id"} { if strings.Contains(locationStable, field) { - t.Fatalf("location stable should only keep protocol/vin identity tags, found %s:\n%s", field, locationStable) + t.Fatalf("location stable should only keep core location columns and protocol/vin tags, found %s:\n%s", field, locationStable) } } } @@ -78,6 +78,10 @@ func TestWriterAppendsRawAndLocationOnly(t *testing.T) { t.Fatalf("location child should not carry raw identity fallback tag %s: %s", field, locationChild) } } + locationInsert := findSQL(exec.calls, "INSERT INTO loc_") + if strings.Contains(locationInsert, "frame_id") || strings.Contains(locationInsert, "go_") { + t.Fatalf("location insert should not duplicate raw frame id: %s", locationInsert) + } } func TestWriterNormalizesPhoneTagAndRefreshesExistingChildTags(t *testing.T) {