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:

  1. the query object itself
  2. the query's stored parameter state
  3. 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:

  • View
  • Property
  • Permission
  • User 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_PROPERTY in 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

OptionWhat it controlsHow to configure itNotes
query_nameMain 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_titleOptional 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_descriptionDescription 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_typePrimary 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.
ownerOwning 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.
publicityReuse 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

OptionWhat it controlsHow to configure itNotes
object_typeType 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_queryWhether 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_querySQL 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_paramsDeclared 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.

OptionWhat it controlsHow to configure itNotes
parametersFull 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.
conditionsStored 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.
orderStored 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_lengthBaseline items-per-page value.Set through pagination-related parameter editing.This is part of stored query state and may also be fixed.
groupsStored grouping configuration.Set through grouping controls in the query builder.Grouping is part of parameter state and can also be fixed.
mergesStored 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_colsStored 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_colsStored columns to hide.Usually configured through hide-column controls.Useful when a baseline query should intentionally suppress some available columns.
select_colsStored 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

OptionWhat it controlsHow to configure itNotes
relevant_viewsViews 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 board
  • Assignable consultants for project form
  • Contracts visible to regional manager

Avoid vague names like:

  • Test query
  • Customer list 2
  • Permission 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 set
  • Property: selector backing set
  • Permission: access-scoping set
  • User 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:

  • System
  • Private
  • Public

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:

  1. String form:
":status:Status" => "pText [active]"

This is parsed as:

  • type
  • optional trailing default in brackets
  1. Structured form:
{
  ":status:Status": {
    "type": "pSelect",
    "default": "active",
    "select_options": {
      "active": "Active",
      "archived": "Archived"
    }
  }
}

The runtime resolves each declared parameter into:

  • name
  • title
  • type
  • default
  • select_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__filters
  • pfix__columns
  • pfix__hideColumns
  • pfix__sorting
  • pfix__groupings
  • pfix__mergings
  • pfix__calculations
  • pfix__tags
  • pfix__page
  • pfix__itemsPerPage

What that means in runtime:

  • fixed parameters are separated into a dedicated fixedParameters object
  • 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:

  1. 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
  1. 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 fixedParameters object
  • 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 Property queries for selectors so their intent is obvious.
  • Name Permission queries 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_params as a stable contract when other builders or integrations depend on the query.