fix(filters): qualify model columns to avoid ambiguity with joins

Qualify plain model columns with the main table alias in resolvespec
filters so preload joins no longer cause SQLSTATE 42702, and accept
<table>.<column> from clients in resolvespec and restheadspec instead
of silently dropping the filter. Add join/preload tests for
resolvespec, restheadspec and funcspec.
This commit is contained in:
2026-10-07 20:58:44 +02:00
parent 3efd539e0f
commit e4c4315f4b
9 changed files with 686 additions and 16 deletions
+55
View File
@@ -0,0 +1,55 @@
package common
import "testing"
type qualifyModel struct {
ID int64 `bun:"id,pk"`
Name string `bun:"name"`
}
func TestQualifyModelColumn(t *testing.T) {
m := qualifyModel{}
cases := []struct{ alias, col, want string }{
{"t", "name", `"t"."name"`},
{"t", "NAME", `"t"."NAME"`},
{"t", "missing", "missing"},
{"t", "data->>'x'", "data->>'x'"},
{"t", "rel.name", "rel.name"},
{"", "name", "name"},
}
for _, c := range cases {
if got := QualifyModelColumn(m, c.alias, c.col); got != c.want {
t.Errorf("Qualify(%q,%q) = %q, want %q", c.alias, c.col, got, c.want)
}
}
if got := QualifyModelColumn(nil, "t", "name"); got != "name" {
t.Errorf("nil model: %q", got)
}
}
func TestStripMainTablePrefix(t *testing.T) {
m := qualifyModel{}
cases := []struct{ col, want string }{
{"province_state.name", "name"},
{`"province_state"."name"`, "name"},
{"PROVINCE_STATE.name", "name"},
{"rel_rid_country.name", "rel_rid_country.name"},
{"province_state.missing", "province_state.missing"},
{"name", "name"},
}
for _, c := range cases {
if got := StripMainTablePrefix(m, c.col, "province_state"); got != c.want {
t.Errorf("Strip(%q) = %q, want %q", c.col, got, c.want)
}
}
}
func TestStripMainTablePrefix_ValidatorKeepsFilter(t *testing.T) {
m := qualifyModel{}
filters := []FilterOption{{Column: "province_state.name", Operator: "eq", Value: "x"}}
StripMainTablePrefixFromFilters(m, filters, "province_state")
out := NewColumnValidator(m).FilterRequestOptions(RequestOptions{Filters: filters})
if len(out.Filters) != 1 || out.Filters[0].Column != "name" {
t.Fatalf("filters = %+v", out.Filters)
}
}