Skip to content

Add query parameter support for read actions#5

Closed
Munksgaard wants to merge 3 commits intoagentjido:mainfrom
Munksgaard:feat/query-params-for-read-actions
Closed

Add query parameter support for read actions#5
Munksgaard wants to merge 3 commits intoagentjido:mainfrom
Munksgaard:feat/query-params-for-read-actions

Conversation

@Munksgaard
Copy link
Copy Markdown
Contributor

@Munksgaard Munksgaard commented Mar 18, 2026

Problem

Generated Jido read actions had no way to filter, sort, or paginate results. An LLM agent calling ListUsers would always get back every record with no ability to narrow results — making read tools impractical for any non-trivial dataset.

Solution

Read actions now accept optional filter, sort, limit, offset, and load parameters that map directly to Ash's query API. These appear in the action's NimbleOptions schema (and therefore in the JSON Schema that LLMs see), so agents can discover and use them through normal tool calling.

Example usage

  # Filter + sort + paginate
  {:ok, users} = ListUsers.run(
    %{
      filter: %{age: %{greater_than: 25}, active: true},
      sort: [name: :asc],
      limit: 10,
      offset: 20,
      load: [:profile]
    },
    %{domain: MyApp.Accounts}
  )
  # => [%{name: "Alice", age: 30, profile: %{bio: "..."}}, ...]

  # Still works with no params (backward compatible)
  {:ok, all_users} = ListUsers.run(%{}, %{domain: MyApp.Accounts})

Security

Query parameters use Ash's safe input variants — Ash.Query.filter_input/2 and Ash.Query.sort_input/2 — which only permit filtering and sorting on public attributes and honor field policies. Private or internal fields cannot be accessed through these parameters.

Configuration

Enabled by default for read actions. Can be controlled per-action or globally:

  jido do
    action :read                            # query params enabled (default)
    action :read, query_params?: false      # opt out
    action :read, max_page_size: 100        # clamp limit to 100

    all_actions read_query_params?: true    # default for all reads
    all_actions read_max_page_size: 100     # max page for all reads
  end

Changes

ad6b1be — DSL options and schema generation

  • Add query_params? (default: true) and max_page_size fields to JidoAction struct
  • Add read_query_params? and read_max_page_size to AllActions struct
  • Add corresponding DSL options to action and all_actions entities
  • Update transformer to propagate new fields for read actions
  • Update build_parameter_schema/4 to append query params to read action schemas
  • 7 new tests for schema generation and opt-out behavior

1359b24 — Runtime execution

  • Update the :read case to split query params from action arguments before Ash.Query.for_read
  • Apply query options via Enum.reduce over individual Ash.Query functions (filter_input, sort_input, limit, offset, load)
  • Enforce max_page_size by clamping the limit value
  • Make test User attributes public?: true (required for filter_input)
  • 13 new runtime integration tests (filter, sort, pagination, combined, max_page_size, backward compat)

dadcd12 — Documentation

  • Add "Query Parameters" section to README with examples and configuration reference
  • Add "Querying and Filtering" section to getting-started guide with filter syntax, sort formats, pagination, and dynamic loading
  • Update DSL option tables in README

Test coverage

20 new tests across schema generation and runtime execution:

Area Tests
Schema: params present/absent/types/docs 7
Filter: equality, greater_than, in, AND 4
Sort: asc, desc 2
Pagination: limit, offset, combined 3
Combined: filter + sort + limit 1
max_page_size: clamp + within bounds 2
Backward compat: empty params 1

All 182 tests pass. mix quality clean (format, compile, credo, dialyzer).

Disclaimer

This PR was written by Claude, but I've looked through it and it seems reasonable.

It might be worth considering whether there should be some protection against misuse, but the language is rather limited, so aside from trying to load every related resource, I don't think there's much an attacker can do.

It might also be worth considering if this behavior should be opt-in rather than opt-out.

Fixes #4

Add query parameter support to generated Jido read actions:

- JidoAction struct: query_params? (default: true), max_page_size fields
- AllActions struct: read_query_params? (default: true), read_max_page_size
- DSL: new options for action and all_actions entities
- Transformer: propagates new fields for read actions
- Generator: appends filter/sort/limit/offset/load params to read schemas
  via new build_query_params_schema/1 helper
- Tests: 7 new tests covering schema generation and opt-out behavior
- Updated existing tests to reflect new default query param presence
Update the :read case in the generated action's execute_action/4 to:
- Split query params (filter/sort/limit/offset/load) from action args
  before passing to Ash.Query.for_read
- Apply query opts via individual Ash.Query functions using Enum.reduce
- Use filter_input/sort_input (safe variants) for security
- Enforce max_page_size by clamping limit values

Helper functions added inside the quoted block:
- split_query_params/2: separates query params from action params
- enforce_max_page_size/2: caps limit to configured max
- apply_query_opts/2: applies each query option to the Ash query

Also makes test User attributes public (required for filter_input).

13 new runtime integration tests covering:
- Filter: equality, greater_than, in, multiple conditions (AND)
- Sort: ascending, descending
- Pagination: limit, offset, combined
- Combined: filter + sort + limit
- max_page_size enforcement (clamp + within bounds)
- Backward compat: empty params
Add Query Parameters section to README.md with:
- Available parameters overview (filter, sort, limit, offset, load)
- Usage example
- Security note (filter_input/sort_input safe variants)
- Configuration examples (query_params?, max_page_size)
- Updated action options and all_actions options tables
- Removed 'pagination or query-layer magic' from 'What It Does Not Do'

Add Querying and Filtering section to guides/getting-started.md with:
- Filter syntax (equality, operators, multiple conditions, IN)
- Sort syntax (keyword list and string formats)
- Pagination (limit + offset)
- Dynamic relationship loading
- Combined example
- Configuration reference
Munksgaard added a commit to Munksgaard/ash_jido that referenced this pull request Apr 1, 2026
Unify PR agentjido#5 (Munksgaard) and PR agentjido#7 (barnabasJ) approaches:

- Rename action_parameters -> query_params (per-action DSL option)
- Rename read_action_parameters -> read_query_params (all_actions DSL option)
- Add Query Parameters section to README.md with examples and config
- Add Querying and Filtering section to getting-started.md guide
- Update DSL option tables in both docs
- Remove 'Add pagination or query-layer magic' from What It Does Not Do

Keeps PR agentjido#7's core logic: compile-time field validation, string key
support, map-based sort format, and ash_json_api-style type checks.
Uses PR agentjido#5's naming convention and documentation style.

All 186 tests pass. mix quality clean.
@mikehostetler
Copy link
Copy Markdown
Contributor

Superseded by #15, which landed the read-action query parameter support on April 1, 2026 with follow-up fixes for tool-style string-key params and JSON sort payloads.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: Support ash query parameters in e.g. read actions to enable filtering, sorting, limiting and so on.

2 participants