Source API
Types below live under InertiaX\Table\Sources;
the source interface is InertiaX\Table\Sources\Contracts\TableSource.
Start with Custom sources to build a repository adapter or
Connect an API source for HTTP request translation.
TableSource
Section titled “TableSource”interface TableSource{ public function fetch(TableQuery $query): TableResult;}Supply an instance, implementing class name, container-bound interface extending TableSource,
or deferred closure returning one through data(). Source instances are reusable strategies and
are not cloned; do not retain request state on a shared instance. Class resolution and options
happen before state validation. fetch() runs after validation. The explicit unavailable-page signal
shows a table-local problem without retrying the source.
Existing model class names retain their Eloquent meaning; an ambiguous model/source class fails.
CallbackSource
Section titled “CallbackSource”CallbackSource::make(Closure $callback): CallbackSource creates an immutable definition.
The callback returns TableResult and selects TableQuery $query, string $tableId, and explicitly
bound services by supported parameter name/type. Optional defaults remain available for ordinary
unresolved dependencies. Required unresolved or ambiguous dependencies fail contextually.
A bare data(fn () => ...) resolves a source earlier; it cannot request TableQuery or return a
TableResult/paginator directly. Use the wrapper for retrieval.
TableQuery
Section titled “TableQuery”TableQuery is final and readonly. InertiaX constructs it from validated table state.
Its public constructor takes the following named arguments; defaults are useful for adapter tests:
sortingLink to sorting- Type
list<array{key: string, direction: 'asc'|'desc'}> - Default / meaning
[]; requested precedence, without an implicit tie-breaker searchableColumnsLink to searchableColumns- Type
list<string> - Default / meaning
[]; declared eligible fields, not arbitrary client fields
offset(): int returns (page - 1) * pageSize, or 0 when pagination is disabled. Overflow fails
before retrieval. effectiveSorting(): array returns requested sorting with one ascending row-key
tie-breaker if an active sort omits it. Empty sorting stays empty.
Each filter group is { operator: 'and'|'or', conditions: [...] }; a child is another group or
{ key, clause, value }. key is the filter’s key, and value matches the clause’s input: null
when it takes none. Repeated fields, nested AND/OR groups, order, native scalar types, and
range/list values are preserved. Values are detached JSON data. Namespaced custom clauses
remain identifiers for the application to translate. Built-in clause meanings should stay consistent.
See Filter groups for bounds and basic/advanced modes.
Constructing a query manually does not perform the Table’s full definition/state validation. Sources should still map trusted fields and reject provider limitations before retrieval. Selection, column visibility, PHP callbacks, provider URLs, and credentials are not query fields.
Search
Section titled “Search”Only columns with type('text') can be searchable with a custom source. A TextColumn changed to
a custom type cannot be searchable on this path. The source implements matching across
searchableColumns using search; searchUsing() callbacks are rejected. Document the provider’s
comparison and collation semantics.
TableResult
Section titled “TableResult”new TableResult(iterable $rows, int $total)Link to new TableResult(iterable $rows, int $total)- Snapshot finite raw array/object records into a list; exact nonnegative JavaScript-safe total
TableResult::all(iterable $rows)Link to TableResult::all- Derive total from all records for unpaginated retrieval
TableResult::fromPaginator(LengthAwarePaginator $paginator, TableQuery $query)Link to TableResult::fromPaginator- Require enabled pagination and matching page/page size; use items and total
The public readonly properties are array $rows and int $total. Record generics preserve array
or object types; readonly does not deep-freeze application record objects. Row keys and column
cell serialization are still validated by the normal pipeline.
Result validation
Section titled “Result validation”totalis the exact number of matching records before pagination, not the length of the page.- Return
min(pageSize, max(0, total - offset))records. Short pages with a larger claimed total and excess rows fail validation. lastPageis derived from the total and page size, with a minimum of 1. Empty results require total0, no rows, and page1. Out-of-range pages fail without clamping or a second fetch.- With
pagination(false), return every matching record and its count.TableResult::all($rows)derives that count. A source may reject unpaginated retrieval explicitly. - Totals must be nonnegative JavaScript-safe integers. Rows must be finite array/object records; missing, duplicate, or invalid identities fail normal row-key validation.
InertiaX does not filter, search, sort, or slice returned rows again. Paginator URLs are ignored; the frontend owns navigation. Unknown totals, simple/cursor paginators, and infinite streams are unsupported. Application code must keep the provider’s page and count consistent.
Filters and options
Section titled “Filters and options”Input modifyUsing() and validateUsing() callbacks run before fetch; their resulting values
must remain JSON data. Values follow Clause validation.
For an application comparison, use Clause::make('acme/in-region')->validateUsing(...) and
translate that key in your source. It needs no SQL callback. A filter’s column() does not reach
the source: map each filter key to the provider’s field there.
Direct Clause/Filter implementations retain definition and value-validation behavior. Their
Eloquent/Collection apply() methods are not invoked. Built-in Boolean storage maps are likewise
not applied to custom results; sources receive the validated Boolean input.
Source-specific options
Section titled “Source-specific options”DataSourceKind::Custom (under Table\Enums) declares custom-source select option support.
options(Closure, DataSourceKind::Custom) supplies the filter, request, resolved TableSource
or CallbackSource, and bound services. Options precede final state validation; named baseSource,
query, and state requests fail with guidance. An options callback may make its own metadata
request, so invalid table state does not guarantee zero metadata I/O. There is no faceting contract.
Explicit option arrays also work. See the API source example.
An options closure typed to a particular source class requires that resolved class. If a per-use
data() override supplies a CallbackSource instead, replace the closure with explicit options
or a compatible callback.
Unsupported configuration
Section titled “Unsupported configuration”autoColumns(), model-derived columns, and select autoOptions() require local model/data
information and fail for custom sources. Automatic filters derived from explicit columns remain
available, without the is-set and is-not-set clauses that nullable database columns get;
advertise only operations the source implements.
sortUsing(), searchUsing(), applyClauseUsing(), and clause applyUsing() conflict with custom
retrieval even if they declare DataSourceKind::Custom support. Put those operations in the source.
Failures and execution
Section titled “Failures and execution”Invalid table state fails before row fetch. Provider exceptions retain source/table/phase context and their original cause. Laravel authentication, authorization, not-found, HTTP, and validation exceptions preserve their response semantics through both source forms.
Server execution fetches once; refreshing starts a new execution. TablePageUnavailableException
produces a table-local problem for Inertia URL pagination without an
automatic retry. Caches and remote retries belong to application code. Browser cancellation does
not guarantee remote cancellation.
See Callback context for injectable arguments and resolution rules.