fix(09): WR-08 search non-text list columns as text instead of failing in SQL
This commit is contained in:
@@ -291,7 +291,9 @@ func applyListSearch(db *gorm.DB, controller pact.AdminController, schema *ListS
|
|||||||
} else if !identifier(column) {
|
} else if !identifier(column) {
|
||||||
return nil, listInvalid("search", "is not searchable")
|
return nil, listInvalid("search", "is not searchable")
|
||||||
}
|
}
|
||||||
parts = append(parts, fmt.Sprintf("LOWER(%s) LIKE ? ESCAPE '\\'", qualifiedColumn(db, table, column)))
|
// CAST makes a numeric, date or boolean column searchable as its text
|
||||||
|
// form (Winter casts to TEXT too); PostgreSQL has no lower(integer).
|
||||||
|
parts = append(parts, fmt.Sprintf("LOWER(CAST(%s AS TEXT)) LIKE ? ESCAPE '\\'", qualifiedColumn(db, table, column)))
|
||||||
args = append(args, pattern)
|
args = append(args, pattern)
|
||||||
}
|
}
|
||||||
return db.Where(strings.Join(parts, " OR "), args...), nil
|
return db.Where(strings.Join(parts, " OR "), args...), nil
|
||||||
|
|||||||
@@ -435,3 +435,45 @@ var _ pact.AdminRecordSource = queryController{}
|
|||||||
var _ pact.AdminPermissioned = queryController{}
|
var _ pact.AdminPermissioned = queryController{}
|
||||||
var _ pact.FilterScope = queryRow{}
|
var _ pact.FilterScope = queryRow{}
|
||||||
var _ pact.FilterOptions = queryRow{}
|
var _ pact.FilterOptions = queryRow{}
|
||||||
|
|
||||||
|
// TestListSearchNonTextColumns pins WR-08: a searchable numeric or date column
|
||||||
|
// is searched as text instead of failing with an SQL error (PostgreSQL has no
|
||||||
|
// lower(integer) or lower(timestamp)).
|
||||||
|
func TestListSearchNonTextColumns(t *testing.T) {
|
||||||
|
svc, db := newListService(t)
|
||||||
|
seedListRows(t, db)
|
||||||
|
const columns = `columns:
|
||||||
|
name:
|
||||||
|
label: Name
|
||||||
|
searchable: true
|
||||||
|
group_id:
|
||||||
|
label: Group
|
||||||
|
searchable: true
|
||||||
|
created_at:
|
||||||
|
label: Created
|
||||||
|
type: datetime
|
||||||
|
searchable: true
|
||||||
|
active:
|
||||||
|
label: Active
|
||||||
|
type: switch
|
||||||
|
searchable: true
|
||||||
|
`
|
||||||
|
schema, err := CompileList("acme.demo", queryController{}, filterFS(queryListConfig, columns, queryFilters))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
svc.reg.byID["acme.demo.widgets"].List = schema
|
||||||
|
|
||||||
|
byGroup := decodeList(t, getList(t, svc, "search=9"), http.StatusOK)
|
||||||
|
if ids := rowIDs(byGroup.Data); len(ids) != 1 || ids[0] != 3 {
|
||||||
|
t.Fatalf("integer column search = %v, want [3]", ids)
|
||||||
|
}
|
||||||
|
byDate := decodeList(t, getList(t, svc, "search=2024-01"), http.StatusOK)
|
||||||
|
if byDate.Meta.Total != 2 {
|
||||||
|
t.Fatalf("timestamp column search total = %d, want 2", byDate.Meta.Total)
|
||||||
|
}
|
||||||
|
byName := decodeList(t, getList(t, svc, "search=other"), http.StatusOK)
|
||||||
|
if ids := rowIDs(byName.Data); len(ids) != 1 || ids[0] != 4 {
|
||||||
|
t.Fatalf("text column search = %v, want [4]", ids)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user