Skip to main content

Parameter binding

Every SQL query and HTTP endpoint receives its values through a consistent parameter model: the connector builder declares the parameters; the page that consumes the connector (a screen, a chart, a dashboard) surfaces them as form inputs; the framework resolves each input through a small chain of fall-backs before running the query.

This page covers how parameters appear in the UI on each surface, where defaults come from, how cascading filters narrow a dropdown based on another, and the special session context every query gets for free.


At a glance

Where does a parameter value come from?1 · CALLERscreen toolbar inputdashboard filterchart fixed valueexplicit user input2 · DEFAULTSdeclared on the connectordate tokens (today, last month…)applied when caller omits3 · SESSION CONTEXTsession.usersession.langsession.rolesalways available, server-side4 · QUERYruns against theresolved parameter map

Declaring a parameter

In Settings → Connectors, open a connector and switch to the Parameters tab. The tab is a table — one row per parameter — with the editor fields below.

tasks → Parameters
Name
Type
Required
Default
Lookup
status
string
open
statuses
✏️
from_date
date
${month.first}
✏️
to_date
date
${month.last}
✏️
Editor fieldDescription
NameThe parameter identifier. Surfaces as the placeholder name in the query (:name) and as the form-input label fallback.
Typestring / int / float / bool / date / datetime / decimal. Drives the widget type on screens (text input vs date picker vs checkbox) and the coercion before the query runs.
LabelDisplay label of the input on the consuming page. Falls back to Name when empty. Localised through the dictionary.
RequiredWhen on, the consuming page must provide a value or the request fails with 400 Bad Request. With Required off, Default fills in when omitted.
DefaultValue applied when the caller omits the parameter. See Defaults.
LookupDropdown of dictionary lookups. When set, the form-input becomes a dropdown of { value, label } pairs from the lookup.
MultipleWhen on, the input accepts a list; the query receives an IN (...) clause.
Filter fromMulti-select of other parameters this one cascades from — see Cascading filters.

Parameters that appear in the query (:name) but aren't declared still bind from the caller — they just have no UI widget and no default. Useful when the value is always set by another mechanism (a chart's fixed value, a job's params).

The connector builder's Parameters tab validates each row in real time — an invalid combination (e.g. Required on without a Default and no Lookup) is flagged before save.


Where parameters surface

A parameter shows up on every page that consumes the connector:

Screens

A screen's toolbar surfaces one input per declared parameter. The widget depends on Type and Lookup:

Type / lookupWidget
stringText input
int / float / decimalNumeric input
boolCheckbox
date / datetimeDate / datetime picker
Any type with Lookup setDropdown populated from the lookup
string + Multiple onMulti-select

The toolbar's Apply / Run button re-runs the read query with the current values. The framework debounces text inputs (~300 ms) so typing doesn't hammer the database.

Charts

Each chart entry has a Fixed parameters panel in its builder. Operators set the value once; the chart always runs against those values. Useful for "Q1 only" or "billing app only" charts. The ${month.first} style tokens are accepted here so the chart tracks the calendar.

Dashboards

Dashboards add a step: the dashboard's Shared filter bar (top of the layout) can expose a parameter once, and every chart referencing the same parameter name inherits the value. Operators see one filter at the top of the dashboard, not one per panel.

Jobs

A job step's Parameters table is the same shape as the connector's declaration — one row per parameter, name read-only, value editable. Substitutions like ${params.period} chain across steps.


Defaults

Three forms of Default are accepted on the connector builder:

FormResolves to
Literalopen, 5, trueThe literal value.
Date token${today}, ${yesterday}, ${week.monday}, ${week.sunday}, ${month.first}, ${month.last}, ${month.previous}The matching date in the server's timezone, re-evaluated at every call. So the default tracks the calendar.
Session value${session.user}, ${session.lang}, ${session.roles}The calling user's identity / language / roles. Documented below.

A Required parameter without a Default and without a caller value causes the call to fail with 400 Bad Request: missing required parameter.


Session context

Three values are always available to every query, even when not declared:

VariableSource
session.userThe sub claim of the JWT — usually the local username or the OIDC email.
session.langThe active language (X-Liberty-Lang header, falling back to the user's preference).
session.rolesA list of the caller's roles.

These are useful for row-level filters that should never come from the user. In the connector builder's Query field, write the query as:

SELECT * FROM contracts WHERE owner = :session_user;

The framework rewrites session.user to the placeholder :session_user at parse time (SQLAlchemy doesn't accept dots in placeholder names).


Cascading filters

A common pattern: a screen has a Company dropdown and a Contract dropdown — the contracts must narrow based on the company. In the connector builder's Parameters tab, set the Contract parameter's Filter from field to company:

Setup
Both parameters set Lookupcompany lookup pulls companies, contract lookup pulls contracts.
Contract sets Filter from = [company].
The lookup query for Contract references :company in its WHERE clause (typically with IS NULL OR to handle the "no company picked" case).

When the operator picks a company, the framework clears the Contract selection and re-fetches the dropdown with the new company. Multiple dependencies are supported — Filter from = [company, region].

The cascade is set up entirely from the dictionary (lookup definitions) and the connector builder; no SQL is written from the consuming screen.


Multiple values

A parameter with Multiple on accepts a list of values and binds it as IN (:name) in the query. The form widget becomes a multi-select.

In the query field, write WHERE status IN (:statuses) — the framework expands the placeholder behind the scenes; the literal IN (:statuses) is what the operator types. An empty list is rejected (the SQL IN () is illegal in most databases); pair Multiple with Required: off + a sensible default to handle the empty case.


How it looks at runtime

For a screen of the tasks connector with no toolbar value set, the framework builds the resolved parameter map at request time:

status = "open" (default)
from_date = 2026-05-01 (date token expanded)
to_date = 2026-05-31 (date token expanded)
session.user = "alice" (session)
session.lang = "en" (session)
session.roles = ["viewer", "editor"] (session)

…and runs the query with it. The browser dev-tools network panel shows the request; the framework's debug logger (with LIBERTY_LOG_LEVEL=DEBUG) prints the resolved parameter map next to the SQL.


Permissions

A query inherits the connector's permission code (sql:<connector>:<query>, api:<connector>:<endpoint>). The framework refuses any call to a query the caller can't run; the consuming page (screen / chart / dashboard) also prunes the surface so the operator doesn't see an unusable widget. See Roles & permissions.


Under the hood

Parameter declarations live on the connector entry inside connectors.toml. Operators do not edit this file by hand; the connector builder is the canonical interface. Advanced operators can reach for the Raw TOML tab as an escape hatch when a builder gap blocks them.


What's next