Expand description
Resolution of a function-backed root query field (#1329).
The engine half of the request:query trigger. A query that declares
function = "<name>" is answered by a
sandboxed function instead of by reading a relation, and this is the seam through
which the engine reaches one — parallel to
BeforeMutationGate, and for the same
reason: fraiseql-core knows nothing about function runtimes, so it holds a
trait object the application supplies. In fraiseql-server that object dispatches
into the compiled schema’s functions section.
§What the engine keeps
Everything except the value. The resolver is asked for the field’s data; the engine still:
- enforces
requires_roleandrequires_actor, before asking; - applies field-level RBAC to what comes back, so a function-backed field is not a hole in the scope gates every other field passes through;
- projects the selection set, recases, and stamps
__typenamewith the same projector the SQL path uses.
That list is the argument for option A in #1329. A field that resolved outside the engine would have to re-implement every one of them, and would be wrong about one of them within a release.
§Root fields only
There is no nested-field equivalent and there will not be one. A nested resolver runs once per row, so a function there is an N+1 measured in V8 isolates — ~5–8 ms each, against a documented cold read of ~5–15 ms for the whole query. Root-only makes “one invocation per query” a property of the shape, and the compiler refuses the nested spelling rather than documenting against it.
Structs§
- Query
Function Request - The field a
QueryFunctionResolveris being asked to answer.
Traits§
- Query
Function Resolver - Answers a function-backed root query field.