Package su.onno.ui

Class WidgetFilter

java.lang.Object
su.onno.ui.WidgetFilter

public final class WidgetFilter extends Object
Parses an authored count/metric-card filter predicate into a safe SQL fragment with bound parameters. The grammar is deliberately small — a chain of field op value comparisons joined by AND — so a dashboard author can write config("filter", "status != cancelled") without the framework ever interpolating user text into SQL.

Injection safety rests on two rules: the left-hand side must be a known column (validated against the entity's columns plus a small system allowlist) matching a strict identifier pattern, and the right-hand value is always a bound parameter. An unrecognised column is skipped with a warning rather than failing the whole card, so a typo degrades to "no filter" instead of an error surface.

  • Method Details

    • parse

      public static WidgetFilter.Result parse(String filter, Set<String> allowedColumns)
      Parameters:
      filter - the authored predicate, e.g. "status != cancelled AND _posted = true"
      allowedColumns - the entity's column names; the system allowlist is added automatically
    • parse

      public static WidgetFilter.Result parse(String filter, Set<String> allowedColumns, Set<String> uuidColumns)
      Like parse(String, Set), but values compared against a column in uuidColumns (ref / enum columns, whose SQL type is UUID) are bound as typed java.util.UUIDs. PostgreSQL rejects a varchar parameter against a uuid column (H2 coerces silently, same class of problem as #163) — the ref picker's cascading refFilter compares record ids, so it passes the ref/enum column set here. A malformed uuid value degrades to a varchar bind (the clause then matches nothing on H2 and errors on PG only for a hand-crafted request).