Skip to content

Stored queries

Fallen-8 has no query language — queries are C# delegates (delegates). A stored query is the precompiled flavor of that: a named, compile-validated definition — either a path filter/cost set or a subgraph pattern template — registered once and afterwards invoked by name from the path and subgraph endpoints, with nothing compiled per request. Each namespace has its own library (namespaces); like every namespace-scoped route, /storedquery also answers under /ns/{ns}/….

flowchart LR
    R["POST /storedquery<br/>compile + validate once"] --> L[("library<br/>per namespace, WAL-durable")]
    L --> P["POST /path/{from}/to/{to}<br/>{ &quot;storedQuery&quot;: &quot;…&quot; }"]
    L --> S["PUT /subgraph<br/>{ &quot;storedQuery&quot;: &quot;…&quot; }"]
Route Effect Notable responses
POST /storedquery Register: validate, compile once, publish 201 summary · 400 malformed or compile failure (body carries compiler diagnostics) · 401 no credential (when a key is configured) · 409 duplicate name or library quota · 413 body over 1 MiB · 429 rate-limited
GET /storedquery List summaries, ordered by name 200
GET /storedquery/{name} Full detail incl. the stored specification JSON (also your migration path between instances) and, for Failed entries, recompile diagnostics 200 · 404
DELETE /storedquery/{name} Deregister 204 · 404

Entries are immutable: to change one, delete and re-register.

Field Required Notes
name yes ^[A-Za-z0-9_-]{1,128}$, case-sensitive, unique per namespace
kind yes Exactly Path or SubGraph
description no Free text, shown in list/detail
path iff kind = Path The filter / cost blocks of a path request
subGraph iff kind = SubGraph The vertexFilter / edgeFilter / patterns of a subgraph request

Exactly one of path / subGraph must be present and must match kind. The fragments inside are the same C# fragments the inline endpoints accept, compiled with the same bounds. Deliberately not stored — these stay per invocation:

  • Path: pathAlgorithmName, maxDepth, maxResults, maxPathWeight, semantic
  • SubGraph: the instance name, additionalInformation

List/detail responses report a compileState: Compiled (invocable), Failed (recompile on load failed — invoking returns 409, diagnostics on the detail; delete and re-register), or SourceOnly (loaded without a compiler, e.g. the embedded engine).

Reference the entry with "storedQuery": "<name>" instead of inline fragments — mutually exclusive with them (400 when mixed):

  • POST /path/{from}/to/{to} accepts a stored query of kind Path; bounds and algorithm come from the request. The semantic block still works — stored fragments read the query vector via their context parameter (semantic traversal).
  • PUT /subgraph accepts a stored query of kind SubGraph and instantiates the template under the request’s name. The created subgraph is self-contained — deleting the stored query later does not affect it. semantic is not available on a stored-template invocation (400); inline the filters instead.

Invocation errors: 404 unknown name, 400 wrong kind, 409 not invocable (Failed/SourceOnly compile state).

Worked example: register once, invoke by name

Section titled “Worked example: register once, invoke by name”

Register a path query that only traverses vertices with age > 30:

curl -X POST http://localhost:8080/storedquery \
-H "Content-Type: application/json" \
-d '{
"name": "adults-shortest",
"kind": "Path",
"description": "age>30 vertices, weight-by-distance",
"path": {
"filter": { "vertexFilter": "return (v) => v.TryGetProperty(out int age, \"age\") && age > 30;" },
"cost": { "edgeCost": "return (e) => 1.0;" }
}
}'

Invoke it — the request carries no code, only the name and per-invocation bounds:

curl -X POST http://localhost:8080/path/1/to/5 \
-H "Content-Type: application/json" \
-d '{ "storedQuery": "adults-shortest", "maxDepth": 5 }'

A subgraph invocation looks the same, with the per-instance name alongside the reference:

PUT /subgraph
{ "name": "adults-2026", "storedQuery": "person-net" }
  • Compile once, invoke many. A fragment is validated and compiled a single time at registration; every invocation reuses the pinned artifact, so a hot query pays no per-request Roslyn cost and callers send only a name plus bounds.
  • A curated catalog. An operator registers a vetted set of named queries that agents and clients reference by name instead of re-sending raw C#, and GET /storedquery lists them for discovery.
  • Portable definitions. GET /storedquery/{name} returns the stored specification JSON — your migration path between instances — and entries survive save/load via the WAL.

Registration carries the same authentication as the inline code endpoints (the API key when one is configured, 401 without it); invocation by name is never gated, since it introduces no new code — the path and subgraph endpoints simply check whether a request carries inline fragments, and a stored-query reference carries none.

Stated honestly: dynamic code execution is always on (there is no switch to lock the engine down to stored-queries-only), and an invoked stored query still runs in-process with full trust. The library is a reuse and curation convenience, not a sandbox. The API key is documented in security.

Registrations and removals are transactions: they survive PUT /save / load and crash recovery via the write-ahead log, with sources recompiled on load (save games).

Limit Value
Library size 256 per namespace (Fallen8:StoredQueries:MaxCount); exceeding it is a 409
Name length 128 characters
Registration body 1 MiB; registration is rate-limited like the other code endpoints
  • Delegates — the no-query-language philosophy, fragment shape, compilation, /delegates/validate
  • Security — the API key that gates access to the code endpoints
  • Path finding · Subgraphs — the endpoints that accept storedQuery
  • Semantic traversal — the semantic block stored path queries can combine with
  • Save games — checkpoints and the write-ahead log
  • Namespaces — per-namespace isolation and the /ns/{ns}/… route twins
  • REST API — OpenAPI document and Scalar reference