refine Semi UI vehicle directory
This commit is contained in:
@@ -73,9 +73,8 @@ func buildVehicleCoverageSQL(query url.Values) SQLQuery {
|
||||
limit := parseSQLPageSize(query.Get("limit"), 20)
|
||||
offset := parsePositive(query.Get("offset"), 0)
|
||||
canonicalSourceCount := strconv.Itoa(len(canonicalVehicleProtocols))
|
||||
args := []any{}
|
||||
vehicleSetSQL, args := buildVehicleCoverageSetSQL(query.Get("scopeVins"))
|
||||
where := []string{"v.vin IS NOT NULL", "v.vin <> ''"}
|
||||
where, args = appendVINListFilter(where, args, "v.vin", query.Get("scopeVins"))
|
||||
having := []string{}
|
||||
if keyword := strings.TrimSpace(query.Get("keyword")); keyword != "" {
|
||||
where = append(where, "(v.vin LIKE ? OR s.plate LIKE ? OR b.vin LIKE ? OR b.plate LIKE ? OR b.phone LIKE ? OR b.oem LIKE ?)")
|
||||
@@ -146,7 +145,6 @@ func buildVehicleCoverageSQL(query url.Values) SQLQuery {
|
||||
if len(having) > 0 {
|
||||
havingSQL = ` HAVING ` + strings.Join(having, " AND ") + ` `
|
||||
}
|
||||
vehicleSetSQL := `SELECT vin FROM vehicle_identity_binding WHERE vin IS NOT NULL AND vin <> ''`
|
||||
groupSQL := `FROM (` + vehicleSetSQL + `) v ` +
|
||||
`LEFT JOIN vehicle_identity_binding b ON b.vin = v.vin ` +
|
||||
`LEFT JOIN vehicle_realtime_snapshot s ON s.vin = v.vin ` +
|
||||
@@ -174,9 +172,8 @@ func buildVehicleCoverageSQL(query url.Values) SQLQuery {
|
||||
|
||||
func buildVehicleCoverageSummarySQL(query url.Values) SQLQuery {
|
||||
canonicalSourceCount := strconv.Itoa(len(canonicalVehicleProtocols))
|
||||
args := []any{}
|
||||
vehicleSetSQL, args := buildVehicleCoverageSetSQL(query.Get("scopeVins"))
|
||||
where := []string{"v.vin IS NOT NULL", "v.vin <> ''"}
|
||||
where, args = appendVINListFilter(where, args, "v.vin", query.Get("scopeVins"))
|
||||
having := []string{}
|
||||
if keyword := strings.TrimSpace(query.Get("keyword")); keyword != "" {
|
||||
where = append(where, "(v.vin LIKE ? OR s.plate LIKE ? OR b.vin LIKE ? OR b.plate LIKE ? OR b.phone LIKE ? OR b.oem LIKE ?)")
|
||||
@@ -245,7 +242,6 @@ func buildVehicleCoverageSummarySQL(query url.Values) SQLQuery {
|
||||
if len(having) > 0 {
|
||||
havingSQL = ` HAVING ` + strings.Join(having, " AND ") + ` `
|
||||
}
|
||||
vehicleSetSQL := `SELECT vin FROM vehicle_identity_binding WHERE vin IS NOT NULL AND vin <> ''`
|
||||
groupSQL := `SELECT v.vin, ` +
|
||||
`COUNT(DISTINCT s.protocol) AS source_count, ` +
|
||||
`COUNT(DISTINCT CASE WHEN s.updated_at >= DATE_SUB(NOW(), INTERVAL 1 MINUTE) THEN s.protocol END) AS online_source_count, ` +
|
||||
@@ -279,6 +275,28 @@ func buildVehicleCoverageSummarySQL(query url.Values) SQLQuery {
|
||||
}
|
||||
}
|
||||
|
||||
func buildVehicleCoverageSetSQL(scope string) (string, []any) {
|
||||
scope = strings.TrimSpace(scope)
|
||||
if scope == "" {
|
||||
return `SELECT vin FROM vehicle_identity_binding WHERE vin IS NOT NULL AND vin <> ''`, nil
|
||||
}
|
||||
vins := splitCSV(scope)
|
||||
if len(vins) == 0 || (len(vins) == 1 && vins[0] == "__NO_VEHICLE_SCOPE__") {
|
||||
return `SELECT CAST(NULL AS CHAR(64)) AS vin WHERE 1 = 0`, nil
|
||||
}
|
||||
selects := make([]string, len(vins))
|
||||
args := make([]any, len(vins))
|
||||
for index, vin := range vins {
|
||||
if index == 0 {
|
||||
selects[index] = `SELECT ? AS vin`
|
||||
} else {
|
||||
selects[index] = `SELECT ?`
|
||||
}
|
||||
args[index] = vin
|
||||
}
|
||||
return `SELECT DISTINCT scoped.vin FROM (` + strings.Join(selects, ` UNION ALL `) + `) scoped`, args
|
||||
}
|
||||
|
||||
func archiveMissingFieldPredicate(field string) string {
|
||||
switch strings.TrimSpace(field) {
|
||||
case "plate":
|
||||
|
||||
@@ -105,6 +105,40 @@ func TestBuildVehicleCoverageSQLIncludesNoDataVehicles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildVehicleCoverageSQLUsesAuthorizedVINsAsPopulation(t *testing.T) {
|
||||
query := url.Values{"scopeVins": {"VIN001,VIN002"}, "limit": {"10"}, "offset": {"20"}}
|
||||
built := buildVehicleCoverageSQL(query)
|
||||
for _, want := range []string{
|
||||
"SELECT DISTINCT scoped.vin",
|
||||
"SELECT ? AS vin UNION ALL SELECT ?",
|
||||
"LEFT JOIN vehicle_identity_binding b ON b.vin = v.vin",
|
||||
"LEFT JOIN vehicle_realtime_snapshot s ON s.vin = v.vin",
|
||||
} {
|
||||
if !strings.Contains(built.Text, want) {
|
||||
t.Fatalf("authorized vehicle coverage SQL missing %q: %s", want, built.Text)
|
||||
}
|
||||
}
|
||||
if strings.Contains(built.Text, "FROM (SELECT vin FROM vehicle_identity_binding") {
|
||||
t.Fatalf("authorized vehicle coverage must not drop granted VINs without identity bindings: %s", built.Text)
|
||||
}
|
||||
if !slices.Equal(built.Args, []any{"VIN001", "VIN002", 10, 20}) {
|
||||
t.Fatalf("args = %#v", built.Args)
|
||||
}
|
||||
if !slices.Equal(built.CountArgs, []any{"VIN001", "VIN002"}) {
|
||||
t.Fatalf("count args = %#v", built.CountArgs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildVehicleCoverageSQLFailsClosedForEmptyAuthorizedScope(t *testing.T) {
|
||||
built := buildVehicleCoverageSQL(url.Values{"scopeVins": {"__NO_VEHICLE_SCOPE__"}})
|
||||
if !strings.Contains(built.Text, "SELECT CAST(NULL AS CHAR(64)) AS vin WHERE 1 = 0") {
|
||||
t.Fatalf("empty authorized scope must use an empty vehicle population: %s", built.Text)
|
||||
}
|
||||
if len(built.Args) != 2 || built.Args[0] != 20 || built.Args[1] != 0 || len(built.CountArgs) != 0 {
|
||||
t.Fatalf("args = %#v count args = %#v", built.Args, built.CountArgs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildVehicleCoverageSQLFiltersMissingProtocol(t *testing.T) {
|
||||
query := url.Values{"missingProtocol": {"YUTONG_MQTT"}, "limit": {"8"}}
|
||||
built := buildVehicleCoverageSQL(query)
|
||||
|
||||
Reference in New Issue
Block a user