Queries
What It Is
A query defines a reusable object-selection contract in Jetstack. It tells the platform which records should be returned, how they may be filtered or ordered, and whether the result set is intended for views, property selectors, permission evaluation, or saved user-facing query templates.
Why It Matters
Queries are one of the main reuse mechanisms in the platform. The same query can shape:
- a table or kanban view
- a relation property's selectable options
- a permission boundary
- a saved user template of a filtered list
That makes query design architectural, not just presentational.
How To Read This Chapter
This chapter explains:
- each main query configuration option
- the meaning of each query role
- how configured and custom queries differ
- how query parameters and fixed query parameters work
Use it together with:
Mental Model
Keep these three layers separate:
- the query object itself
- the query's stored parameter state
- the user or view runtime state layered on top of it
This distinction is especially important for fixed parameters:
- a regular query parameter is part of the query's baseline state and may later be overridden by runtime state
- a fixed query parameter is still part of the query state, but it is also marked as locked so downstream views treat it as non-overridable and apply it first
Query Roles
Jetstack defines four query roles:
ViewPropertyPermissionUser template
The code explicitly describes this as categorization of the query by its primary intended use.
View
Use this role for queries whose main purpose is to feed views.
This is the default query role.
Typical uses:
- list pages
- board views
- calendar-style views
- standard data-display surfaces
What it means in the platform:
- these are the most general reusable queries
- they are the normal baseline for
View.relevant_queries - they often hold durable list behavior such as default filters, columns, sorting, groupings, and tags
Choose View when the query is primarily about presenting or navigating a result set.
Property
Use this role for queries whose main purpose is to provide selectable options to a property.
Typical uses:
- relation selectors
- dynamic option lists
- filtered pickers for object references
What it means in the platform:
- property option queries are explicitly filtered to
query_type = QT_PROPERTYin the property-type runtime - these queries should usually be narrow, predictable, and safe for selector contexts
- they often pair with Properties, especially
options_query,title_property,value_switch, and conditional selector behavior
Choose Property when the query exists primarily to populate a field, not to serve as a user-facing list.
Permission
Use this role for queries whose main purpose is to define access scope.
Typical uses:
- "user can edit only contracts from their department"
- "role can see only non-archived projects assigned to its region"
- "property action is allowed only on matching records"
What it means in the platform:
- permission presenters explicitly list and use queries of this role
- query creation shortcuts inside permission UIs prefill
query_type = Permission - the query becomes part of the security model, not just data presentation
Choose Permission when the result set defines who may access what.
User template
Use this role for saved user-facing query states.
Typical uses:
- saved personal list templates
- saved view filters
- reusable public or private list states created from filter UIs
What it means in the platform:
- the filters control creates saved queries with
query_type = User template - these are often created from an already active view state
- they usually store parameter state rather than model-level business logic
Choose User template when the query is primarily a saved slice of a list experience, not a core implementation asset.
Query Configuration Options
The fields below come from the query resource definition and the query create/edit flow.
Identity And Intent
| Option | What it controls | How to configure it | Notes |
|---|---|---|---|
query_name | Main name of the query. | Enter a stable, descriptive name such as Active customers for selector, Contracts editable by owner, or Open invoices board. | This is the title-role field and the most important identifier used by implementers. |
query_title | Optional display title of the query. | Enter a friendlier or more presentation-oriented title if needed. | If left null, the runtime falls back to query_name. |
query_description | Description of the query's purpose. | Describe what the query returns and why it exists. | This is especially valuable for permission and property queries where intent is not obvious from conditions alone. |
query_type | Primary intended role of the query. | Choose one of View, Property, Permission, or User template. | This is required. It is a categorization field, but it also matters because several parts of the platform filter or create queries by this role. |
owner | Owning user for personal/private query scenarios. | Set this when the query should belong to a specific user. | This field comes from the broader system-resource surface and matters especially for private and user-template queries. |
publicity | Reuse and visibility level of the query. | Choose System, Private, or Public. | Use this to decide whether the query is an internal platform asset, a private user asset, or a reusable shared one. |
Query Target And Runtime Mode
| Option | What it controls | How to configure it | Notes |
|---|---|---|---|
object_type | Type of objects returned by the query. | Select the target type the query should operate on. | This is required. Almost every other query behavior depends on this. |
is_custom_query | Whether the query uses custom SQL rather than only configured query parameters. | Enable when the standard configured-query model is not sufficient. | When this is enabled, the custom SQL fields become relevant. |
custom_query | SQL text used for a custom query. | Enter the SQL in the custom query editor. | Visible only when is_custom_query is enabled. Use this only when the configured query model cannot express the needed behavior. |
custom_query_available_params | Declared parameter contract for a custom query. | Define the available parameters as a struct/array. | This makes custom SQL reusable and parameterized instead of hard-coded. |
Stored Parameter State
These fields store the baseline query state. They are mostly internal in the resource definition, but they are important because they represent what the query builder persists.
| Option | What it controls | How to configure it | Notes |
|---|---|---|---|
parameters | Full stored query parameter payload. | Usually configured through the query builder, filters UI, or query runtime state rather than manual direct editing. | This is the most important stored state field for configured queries. |
conditions | Stored low-level conditions for the query object. | Usually created by the query builder or query methods rather than hand-edited. | Think of this as internal query structure rather than business-facing configuration. |
order | Stored ordering rules. | Set through sorting configuration in the query builder or runtime parameter flow. | Ordering may also be supplemented later by runtime sort parameters. |
page_length | Baseline items-per-page value. | Set through pagination-related parameter editing. | This is part of stored query state and may also be fixed. |
groups | Stored grouping configuration. | Set through grouping controls in the query builder. | Grouping is part of parameter state and can also be fixed. |
merges | Stored merge or GROUP BY-like configuration. | Set through merge/grouping builder controls. | Merging has its own parameter family and is separate from ordinary grouping. |
show_cols | Stored columns to show. | Usually configured through visible-column selection in the query/view builder. | These are baseline display columns, not necessarily the final runtime columns after user overrides. |
hide_cols | Stored columns to hide. | Usually configured through hide-column controls. | Useful when a baseline query should intentionally suppress some available columns. |
select_cols | Stored explicit select-column set. | Used when the query should explicitly select a known set of columns. | More internal and lower-level than ordinary display-column selection. |
Relevance And Reuse
| Option | What it controls | How to configure it | Notes |
|---|---|---|---|
relevant_views | Views that are associated with this query. | The relationship is managed through view/query linking. | This is a virtual relationship from View.relevant_queries. It helps explain where the query is expected to be used. |
Option Details
query_name
This should describe both the data set and the reason it exists.
Good examples:
Open invoices for finance boardAssignable consultants for project formContracts visible to regional manager
Avoid vague names like:
Test queryCustomer list 2Permission thing
The more strategic the query role, the more important clear naming becomes.
query_type
This is one of the most important fields on the query because it tells future implementers how to reason about the query.
Use it as an explicit statement of design intent:
View: presentation-oriented reusable data setProperty: selector backing setPermission: access-scoping setUser template: saved end-user or view-state set
If a query could be used in multiple places, choose the role that best describes why it was created in the first place.
publicity
Available values:
SystemPrivatePublic
Use them like this:
System: platform-owned or implementation-owned query. Best for durable shared logic.Private: personal or owner-scoped query that should not be treated as general reusable infrastructure.Public: reusable shared query available as a tenant-level asset.
This matters especially for user templates and shared view presets.
object_type
This is the target model of the query.
It determines:
- which properties can be filtered or shown
- which sort and grouping options make sense
- which property-family filter operators apply
- which related views and properties can reuse the query
Changing object_type after a query is already in use is usually disruptive, because the entire parameter surface is type-dependent.
is_custom_query
Enable this only when the configured query model is not enough.
Good reasons:
- the data needs SQL constructs the builder does not express well
- you need a very specific join or computed column model
- the query is integration-like or analytical in a way that exceeds ordinary property filters
Bad reasons:
- the builder UI feels slower than writing SQL
- the query could be modeled clearly with standard filters
- the team has not yet tried to express it as a configured query
custom_query
This stores SQL text and is shown in a code editor when custom-query mode is enabled.
Use it with care:
- it is more powerful
- but it is also less transparent to non-SQL implementers
- and it changes how parameters are applied at runtime
Important runtime behavior:
- ordinary query-parameter application is skipped for custom queries unless the parent component explicitly forces parameter application
- instead, the runtime usually injects SQL parameters into the custom query
That means custom queries are not just "configured queries with extra freedom." They follow a meaningfully different runtime path.
custom_query_available_params
This is the declared parameter contract for a custom SQL query.
The resource description says it is an array where:
- keys are parameter names
- values describe their types as something like
"pX [default]"
The query runtime also supports array-style parameter definitions with richer structure.
Supported shapes:
- String form:
":status:Status" => "pText [active]"
This is parsed as:
- type
- optional trailing default in brackets
- Structured form:
{
":status:Status": {
"type": "pSelect",
"default": "active",
"select_options": {
"active": "Active",
"archived": "Archived"
}
}
}
The runtime resolves each declared parameter into:
nametitletypedefaultselect_options
Parameter-name behavior:
- if the key starts with
:, the runtime treats it as a named parameter definition - the part after
:can contain both machine name and title, separated by another: - if the key does not start with
:, the runtime treats it as a positional parameter title and assigns a numeric parameter name
This is how custom SQL stays reusable instead of becoming hard-coded per use.
Configured Queries Versus Custom Queries
Configured Query
A configured query is primarily driven by stored query parameters:
- filters
- columns
- hidden columns
- sorting
- grouping
- merging
- calculations
- tags
- pagination
Use configured queries when:
- the logic is about selecting and presenting typed objects
- property-aware filter semantics are valuable
- views and users may want to refine the query later
Custom Query
A custom query is primarily driven by SQL text and declared custom parameters.
Use custom queries when:
- the result shape requires explicit SQL
- the builder cannot clearly represent the logic
- the query is specialized enough that SQL is the clearest contract
Configured queries are usually better for:
- maintainability
- discoverability
- property-aware filters
- downstream reuse by views and properties
Custom queries are usually better for:
- specialized data retrieval
- nonstandard joins
- advanced SQL-driven shaping
Regular Query Parameters Versus Fixed Query Parameters
This is one of the most important distinctions in the query system.
Regular Query Parameters
Regular query parameters are ordinary stored parameter values, such as:
- visible columns
- filters
- sorting
- grouping
- tags
- pagination
They define the baseline state of the query.
At runtime, those parameters may later be supplemented or overridden by:
- user-selected filter state
- view state
- shared links
- saved user-template state
Fixed Query Parameters
Fixed query parameters are query parameters that are also marked as locked.
They are still represented through the same parameter families, but the system additionally stores fixed-parameter metadata in pfix_* fields such as:
pfix__filterspfix__columnspfix__hideColumnspfix__sortingpfix__groupingspfix__mergingspfix__calculationspfix__tagspfix__pagepfix__itemsPerPage
What that means in runtime:
- fixed parameters are separated into a dedicated
fixedParametersobject - they are applied before ordinary runtime parameters
- when fixed-parameter locking is active in the data-display layer, they are treated as non-overridable baseline constraints
- they are also hidden from the ordinary adjustable parameter set so user-facing state mainly works with the non-fixed query parameters
In plain terms:
- regular parameter = baseline preference
- fixed parameter = baseline rule
How A Query Parameter Is Marked As Fixed
There are two important paths:
- Programmatic query methods
Some query helper methods explicitly allow a fixed flag:
setParam_grouping(..., fixed: true)setParam_displayCols(..., fixed: true)setParam_hideCols(..., fixed: true)setParam_tags(..., fixed: true, ...)
When you pass fixed: true, the query writes both:
- the normal parameter value
- the matching
pfix__...metadata
- Query builder UI
The query builder exposes a dedicated fixed-parameters form where implementers can mark:
- filters
- columns
- hidden columns
- sorting
- groupings
- mergings
- calculations
- page
- items per page
- limit
- offset
as fixed.
This is how most implementers will encounter the feature.
What Fixed Actually Changes
When a view loads a query:
- the query's stored parameters are parsed into
viewQueryParameters - user-provided parameters are parsed into
userQueryParameters - fixed parameters are extracted into a dedicated
fixedParametersobject - fixed parameters are applied first
- regular query parameters and user parameters are then consolidated on top
This is why fixed parameters are the right tool when a query must enforce:
- a permanent security or business constraint
- a mandatory grouping baseline
- a required tag or folder scope
- a locked presentation column set
This is also why fixed parameters are not the right tool when you only want a helpful default.
Typical Query Design Patterns
View Query
Use:
query_type = View- configured filters and display columns
- optional fixed groupings or tags only when the view must always keep them
This is the standard list/query pattern.
Property Selector Query
Use:
query_type = Property- clear object type
- minimal columns
- filters that keep the selector stable and understandable
This query should optimize for option quality, not for list exploration.
Query Result Field
Use:
- a query scoped to the owning record (for example a filter like
{$this.id}) - an optional calculation when the field should show a sum or distinct count instead of a row count
Bind this query to a Query Result Property to show a count, list, or set of links of related records directly on a record.
Permission Query
Use:
query_type = Permission- descriptive naming
- conditions tied to role, ownership, status, or organizational scope
- fixed behavior where user override would be unsafe
This query is part of the access-control model.
User Template Query
Use:
query_type = User template- private or public publicity as appropriate
- parameter-heavy state captured from a view
This is a saved slice of a list experience, not usually a core model asset.
Best Practices
- Choose the query role based on why the query exists, not just where it might be reused later.
- Prefer configured queries until custom SQL is genuinely necessary.
- Use
Propertyqueries for selectors so their intent is obvious. - Name
Permissionqueries as policy statements, not generic data sets. - Use fixed parameters only for rules that downstream users should not override.
- Use regular parameters for defaults that users are expected to refine.
- Treat
custom_query_available_paramsas a stable contract when other builders or integrations depend on the query.