Queries — overview
A query in Liberty is a named SQL statement attached to a connector (which itself points at a pool, i.e. a database). Screens, dashboards, charts, dictionary lookups, dictionary sequences and the AI assistant all consume queries — so adding a query is the most common change you'll make in the Settings UI.
The page that manages queries is Settings → Connectors. This overview maps it; the next pages walk through each "add" path.
The Connectors page at a glance
Three regions:
| Region | What it carries |
|---|---|
| Top toolbar | Global actions — + Connector, Discard, Save. The Save button writes the connector file and triggers a hot reload — no process restart needed. |
| Left navigation | Two groups: Apps (connectors that have a menu — these are the apps users see in the top switcher) and Data sources (connectors that supply data but don't appear in the switcher). Click a name to open it on the right. |
| Right pane | The editor for the selected connector. A mode bar across the top picks one of five views — Settings, Tables, Unclassified, Sequences, Lookups. |
The four kinds of queries
Every query carries a type that tells the page which tab it belongs to:
| Tab | type | What lives here |
|---|---|---|
| Tables | table | Queries that follow the CRUD naming convention — <base>_get, <base>_put, <base>_post, <base>_delete. The page groups them by base name and shows a row per table with four slot badges (GET / PUT / POS / DEL). |
| Unclassified | custom | Standalone queries not tied to a table CRUD set — bulk operations, business queries, reports. Example: monthly_revenue, purge_old_logs. |
| Sequences | sequence | Queries that generate the next value for a dictionary [sequences.*] rule. Typical body: SELECT COALESCE(MAX(<col>), 0) + 1 FROM <table>. |
| Lookups | lookup | Queries that supply value + label pairs for a dictionary [lookups.*] rule. Typical body: SELECT <value>, <label> FROM <table>. |
The tab the query falls into is decided by its type — not by its name. A query named customer_balance typed custom lives in Unclassified; the same name typed lookup lives in Lookups.
The add buttons — one per tab
The Add affordance is per tab, because each kind has its own creation flow.
| Tab | Add button | What opens |
|---|---|---|
| Tables | + Add table | A choice modal: Generate from DB (the CRUD Wizard — introspects the pool, generates all four queries) or Empty stub (prompts a base name, creates a blank <base>_get stub). |
| Unclassified | + Add query | A name prompt — creates a blank custom query you fill in by hand. |
| Sequences | + Add sequence | The Scaffold modal — pick a table, pick a key column, get a live SQL preview, save (writes the query and the matching dictionary entry). |
| Lookups | + Add lookup | The Scaffold modal — pick a table, pick a value column and a label column, optional WHERE filter, save (writes the query and the dictionary entry). |
The next pages walk through each path.
What a query carries
The editor form (Unclassified / Sequences / Lookups tabs) reflects the QueryDef shape:
| Field | Required | What it does |
|---|---|---|
name | Yes | Unique inside the connector. The permission string for this query is sql:<connector>:<name>. Read-only in the editor — use the Rename button (cross-file rename). |
type | No | table / custom / sequence / lookup — drives which tab the query appears on. Empty falls back to a name-based guess. |
sql | Yes | The SQL statement with :placeholder parameters. Can be a single string, or a per-dialect map { default = "…", oracle = "…" }. The default variant is required when using a map. |
writable | No (default false) | When false, only SELECT is allowed. Flip to true for INSERT / UPDATE / DELETE / CALL. |
params | No | List of declared parameters (name, label, default) — gives each :placeholder a form input. |
label | No | Short name shown in dropdowns and listings. |
description | No | Longer text — shown on the Tables list under the base name. Use it to explain what the query returns. |
Save and reload — what a click does
Saving on this page is atomic across two files when needed:
| Action you took | What gets written |
|---|---|
| Created or edited a query under Tables / Unclassified | The connector file. |
| Used the Scaffold for a sequence or lookup | The connector file and the dictionary file (the new entry under [connectors.<name>.sequences] or [connectors.<name>.lookups]). |
| Cloned a connector (whole app) | A cross-file write that copies the dictionary overlay, screens, menu, charts and dashboards under the new name. Goes through a dedicated endpoint. |
| Renamed a connector, a query or a table | A cross-file update that touches every reference (screens, menus, dictionary, charts, dashboards). Refuses to run when local edits aren't saved. |
After every save the framework runs a hot reload automatically. The new query is callable immediately — no restart, no logout.
What you actually do — quick map
| Goal | Read |
|---|---|
| Generate the four CRUD queries from a real database table. | Create from a database table — the wizard path, recommended when the table exists. |
| Write a custom query (standalone, hand-written). | Create a custom query. |
| Make a copy of an existing query or of a whole application. | Clone a query or a connector. |
| Add a sequence (next id) or a lookup (dropdown source). | Sequences and lookups. |
Pass values to a query — both literal and bound (#LOGIN_USER#, source columns…). | Parameter binding. |
| Ship different SQL for Postgres vs Oracle. | Per-dialect SQL variants. |
What's next
- Create from a database table — start here when the table already lives in your database.
- Concepts → Connectors — the deep reference behind this page (connector kinds, pools, query lifecycle).