diff --git a/go/vehicle-gateway/internal/realtime/repository.go b/go/vehicle-gateway/internal/realtime/repository.go index 6d629779..afd92a65 100644 --- a/go/vehicle-gateway/internal/realtime/repository.go +++ b/go/vehicle-gateway/internal/realtime/repository.go @@ -364,7 +364,7 @@ func asAnySlice(value any) ([]any, bool) { } func mergeSliceKey(item map[string]any) string { - for _, key := range []string{"name", "type", "id"} { + for _, key := range []string{"name", "type", "id", "serial_no"} { if value, ok := item[key]; ok { text := strings.TrimSpace(strconvAny(value)) if text != "" { diff --git a/go/vehicle-gateway/internal/realtime/repository_test.go b/go/vehicle-gateway/internal/realtime/repository_test.go index 7734f1f8..00df53c8 100644 --- a/go/vehicle-gateway/internal/realtime/repository_test.go +++ b/go/vehicle-gateway/internal/realtime/repository_test.go @@ -129,6 +129,73 @@ func TestRepositoryStoresFullParsedProtocolSnapshotAndMergesGB32960Units(t *test } } +func TestRepositoryMergesNestedGB32960MotorSlicesBySerialNo(t *testing.T) { + repo, closeFn := newTestRepository(t) + defer closeFn() + ctx := context.Background() + + if err := repo.Update(ctx, envelope.FrameEnvelope{ + Protocol: envelope.ProtocolGB32960, + VIN: "VIN001", + EventTimeMS: 1000, + ReceivedAtMS: 1100, + Parsed: map[string]any{ + "data_units": []any{ + map[string]any{ + "type": "0x02", + "name": "drive_motor", + "value": map[string]any{ + "motors": []any{ + map[string]any{"serial_no": 1, "speed_rpm": 5000}, + map[string]any{"serial_no": 2, "speed_rpm": 5100}, + }, + }, + }, + }, + }, + }); err != nil { + t.Fatalf("Update() error = %v", err) + } + if err := repo.Update(ctx, envelope.FrameEnvelope{ + Protocol: envelope.ProtocolGB32960, + VIN: "VIN001", + EventTimeMS: 1100, + ReceivedAtMS: 1200, + Parsed: map[string]any{ + "data_units": []any{ + map[string]any{ + "type": "0x02", + "name": "drive_motor", + "value": map[string]any{ + "motors": []any{ + map[string]any{"serial_no": 1, "speed_rpm": 5406}, + map[string]any{"serial_no": 2, "speed_rpm": 5377}, + }, + }, + }, + }, + }, + }); err != nil { + t.Fatalf("Update() error = %v", err) + } + + realtimeRaw, err := repo.GetRealtimeRaw(ctx, "VIN001", envelope.ProtocolGB32960) + if err != nil { + t.Fatalf("GetRealtimeRaw() error = %v", err) + } + units := realtimeRaw["data_units"].([]any) + driveMotor := units[0].(map[string]any) + value := driveMotor["value"].(map[string]any) + motors := value["motors"].([]any) + if len(motors) != 2 { + t.Fatalf("motors len = %d, want 2: %#v", len(motors), motors) + } + first := motors[0].(map[string]any) + if first["speed_rpm"] != float64(5406) { + t.Fatalf("first motor was not updated: %#v", motors) + } +} + func TestRepositoryOnlineStatus(t *testing.T) { repo, closeFn := newTestRepository(t) defer closeFn()