fix: filter raw frames by vehicle key

This commit is contained in:
lingniu
2026-07-02 00:24:53 +08:00
parent f3ecf430cc
commit cc89e0d537
2 changed files with 70 additions and 25 deletions

View File

@@ -17,15 +17,16 @@ type Queryer interface {
} }
type RawFrameQuery struct { type RawFrameQuery struct {
Protocol string Protocol string
VIN string VehicleKey string
Phone string VIN string
DeviceID string Phone string
MessageID string DeviceID string
DateFrom string MessageID string
DateTo string DateFrom string
Limit int DateTo string
Offset int Limit int
Offset int
} }
type RawFrameRow struct { type RawFrameRow struct {
@@ -123,6 +124,7 @@ func (r *RawFrameRepository) tableName() string {
func normalizeRawFrameQuery(query RawFrameQuery) RawFrameQuery { func normalizeRawFrameQuery(query RawFrameQuery) RawFrameQuery {
query.Protocol = strings.ToUpper(strings.TrimSpace(query.Protocol)) query.Protocol = strings.ToUpper(strings.TrimSpace(query.Protocol))
query.VehicleKey = strings.TrimSpace(query.VehicleKey)
query.VIN = strings.TrimSpace(query.VIN) query.VIN = strings.TrimSpace(query.VIN)
query.Phone = strings.TrimSpace(query.Phone) query.Phone = strings.TrimSpace(query.Phone)
query.DeviceID = strings.TrimSpace(query.DeviceID) query.DeviceID = strings.TrimSpace(query.DeviceID)
@@ -143,6 +145,9 @@ func buildRawFrameSQL(table string, query RawFrameQuery) (string, []any) {
if query.Protocol != "" { if query.Protocol != "" {
add("protocol = '" + quote(query.Protocol) + "'") add("protocol = '" + quote(query.Protocol) + "'")
} }
if query.VehicleKey != "" {
add("vehicle_key = '" + quote(query.VehicleKey) + "'")
}
if query.VIN != "" { if query.VIN != "" {
add("vin = '" + quote(query.VIN) + "'") add("vin = '" + quote(query.VIN) + "'")
} }
@@ -221,15 +226,16 @@ func parseRawFrameQuery(r *http.Request) (RawFrameQuery, error) {
return RawFrameQuery{}, err return RawFrameQuery{}, err
} }
query := RawFrameQuery{ query := RawFrameQuery{
Protocol: values.Get("protocol"), Protocol: values.Get("protocol"),
VIN: values.Get("vin"), VehicleKey: values.Get("vehicleKey"),
Phone: values.Get("phone"), VIN: values.Get("vin"),
DeviceID: values.Get("deviceId"), Phone: values.Get("phone"),
MessageID: values.Get("messageId"), DeviceID: values.Get("deviceId"),
DateFrom: values.Get("dateFrom"), MessageID: values.Get("messageId"),
DateTo: values.Get("dateTo"), DateFrom: values.Get("dateFrom"),
Limit: limit, DateTo: values.Get("dateTo"),
Offset: offset, Limit: limit,
Offset: offset,
} }
if !validDateTime(query.DateFrom) || !validDateTime(query.DateTo) { if !validDateTime(query.DateFrom) || !validDateTime(query.DateTo) {
return RawFrameQuery{}, errors.New("dateFrom/dateTo must use YYYY-MM-DD or YYYY-MM-DD HH:mm:ss") return RawFrameQuery{}, errors.New("dateFrom/dateTo must use YYYY-MM-DD or YYYY-MM-DD HH:mm:ss")

View File

@@ -94,6 +94,43 @@ func TestRawFrameHandlerReturnsRawFrames(t *testing.T) {
} }
} }
func TestRawFrameHandlerFiltersByVehicleKey(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("sqlmock.New() error = %v", err)
}
defer db.Close()
mock.ExpectQuery("vehicle_key = 'JT808:013307811350'").
WillReturnRows(sqlmock.NewRows([]string{
"ts", "frame_id", "event_id", "message_id", "event_time", "received_at", "raw_size_bytes",
"raw_hex", "raw_text", "parsed_json", "fields_json", "parse_status", "parse_error", "source_endpoint",
"protocol", "vehicle_key", "vin", "phone", "device_id",
}).AddRow(
"2026-07-02 00:18:22", "go_frame", "event-3", 0x0200, "2026-07-02 00:18:22", "2026-07-02 00:22:43",
63, "7E0200", "", `{"header":{"message_id":"0x0200"}}`, `{"total_mileage_km":8792.8}`,
"OK", "", "115.231.168.135:22170", "JT808", "JT808:013307811350", "", "013307811350", "",
))
handler := NewRawFrameHandler(NewRawFrameRepository(db, "lingniu_vehicle_ts"))
request := httptest.NewRequest(http.MethodGet, "/api/history/raw-frames?vehicleKey=JT808:013307811350&protocol=JT808&limit=1", nil)
response := httptest.NewRecorder()
handler.ServeHTTP(response, request)
if response.Code != http.StatusOK {
t.Fatalf("status = %d body=%s", response.Code, response.Body.String())
}
body := response.Body.String()
for _, want := range []string{`"vehicle_key":"JT808:013307811350"`, `"phone":"013307811350"`, `"total":1`} {
if !strings.Contains(body, want) {
t.Fatalf("response missing %s: %s", want, body)
}
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("sql expectations: %v", err)
}
}
func TestRawFrameHandlerRejectsInvalidLimit(t *testing.T) { func TestRawFrameHandlerRejectsInvalidLimit(t *testing.T) {
handler := NewRawFrameHandler(NewRawFrameRepository(&sql.DB{}, "")) handler := NewRawFrameHandler(NewRawFrameRepository(&sql.DB{}, ""))
request := httptest.NewRequest(http.MethodGet, "/api/history/raw-frames?limit=501", nil) request := httptest.NewRequest(http.MethodGet, "/api/history/raw-frames?limit=501", nil)
@@ -121,19 +158,21 @@ func TestParseMessageIDSupportsDecimalAndHex(t *testing.T) {
func TestBuildRawFrameSQLUsesLiteralsForTDengine(t *testing.T) { func TestBuildRawFrameSQLUsesLiteralsForTDengine(t *testing.T) {
sqlText, args := buildRawFrameSQL("lingniu_vehicle_ts.raw_frames", RawFrameQuery{ sqlText, args := buildRawFrameSQL("lingniu_vehicle_ts.raw_frames", RawFrameQuery{
Protocol: "JT808", Protocol: "JT808",
VIN: "VIN'1", VehicleKey: "JT808:013307811350",
MessageID: "0x0200", VIN: "VIN'1",
DateFrom: "2026-07-01 00:00:00", MessageID: "0x0200",
DateTo: "2026-07-01 23:59:59", DateFrom: "2026-07-01 00:00:00",
Limit: 20, DateTo: "2026-07-01 23:59:59",
Offset: 5, Limit: 20,
Offset: 5,
}) })
if len(args) != 0 { if len(args) != 0 {
t.Fatalf("expected no query args for TDengine, got %#v", args) t.Fatalf("expected no query args for TDengine, got %#v", args)
} }
for _, want := range []string{ for _, want := range []string{
"protocol = 'JT808'", "protocol = 'JT808'",
"vehicle_key = 'JT808:013307811350'",
"vin = 'VIN''1'", "vin = 'VIN''1'",
"message_id = 512", "message_id = 512",
"LIMIT 20 OFFSET 5", "LIMIT 20 OFFSET 5",