query_graph: add split / substring — the Cypher subset can filter rows but not shape them
Version: 0.10.8 (macOS, single static binary)
What happens
query_graph(query='MATCH (f:Function) WHERE f.qualified_name CONTAINS "safe_null"
RETURN split(f.qualified_name, ".") AS parts LIMIT 3', project="…")
→ unsupported function 'split' (supported: count, sum, avg, min, max, collect, toLower,
toUpper, toString, toInteger, toFloat, toBoolean, size, length, trim, ltrim, rtrim,
reverse, labels, type, id, keys, properties)
The error is good — it prints the whole supported list, which is how I knew immediately what I had
to work with rather than guessing function by function.
The gap the list shows
That vocabulary covers predicates well and projection barely. Everything string-shaped in it
either tests a value (toLower for case-insensitive comparison), measures one (size, length), or
strips whitespace (trim, ltrim, rtrim). Nothing takes a piece out of a string.
reverse is the tell: a function that manipulates a string is already in the evaluator, so this is
a coverage gap in an existing capability rather than a new class of feature.
Why it matters for this tool specifically
Qualified names are long, and this graph is largely made of them. A query that wants the last
segment of packages/cloudbay-core-cli/frontend/src/pages/action-set-run-view.PermutationDetail,
or the module prefix without the leaf, cannot express it — so the rows come back at full width and
the caller either post-processes them or reads 200-character lines.
That post-processing is exactly the thing an MCP backend is supposed to make unnecessary. The rows
are already crossing the wire at full length and being paid for in tokens, and the trimming that
would have made them readable is a string operation the query could have done at the source.
Concretely, what I wanted was shape-the-output, not filter-the-rows:
MATCH (f:Function)
WHERE f.transitive_loop_depth >= 3
RETURN split(f.qualified_name, ".")[-1] AS name, f.transitive_loop_depth
ORDER BY f.transitive_loop_depth DESC
Suggested fix
In rough order of how much each one buys:
split(string, delimiter) → list — the one that unlocks qualified-name handling.
substring(string, start [, length]) — the general escape hatch; with size already present
it covers most truncation without a dedicated function.
replace(original, search, replacement) — commonly paired with the two above.
left / right — sugar over substring, only if they are cheap.
split alone would cover most of it. If list indexing on a split result is not supported by the
evaluator, substring plus the existing size is a workable substitute and may be the smaller
change.
Severity
Minor. Nothing here is wrong or misleading — it is a ceiling on what the query language can express,
and the error message makes the ceiling visible immediately rather than letting someone discover it
by trial. Filing it because the fix looks small relative to how often long qualified names come up
in a graph whose primary key is a qualified name.
query_graph: addsplit/substring— the Cypher subset can filter rows but not shape themVersion: 0.10.8 (macOS, single static binary)
What happens
The error is good — it prints the whole supported list, which is how I knew immediately what I had
to work with rather than guessing function by function.
The gap the list shows
That vocabulary covers predicates well and projection barely. Everything string-shaped in it
either tests a value (
toLowerfor case-insensitive comparison), measures one (size,length), orstrips whitespace (
trim,ltrim,rtrim). Nothing takes a piece out of a string.reverseis the tell: a function that manipulates a string is already in the evaluator, so this isa coverage gap in an existing capability rather than a new class of feature.
Why it matters for this tool specifically
Qualified names are long, and this graph is largely made of them. A query that wants the last
segment of
packages/cloudbay-core-cli/frontend/src/pages/action-set-run-view.PermutationDetail,or the module prefix without the leaf, cannot express it — so the rows come back at full width and
the caller either post-processes them or reads 200-character lines.
That post-processing is exactly the thing an MCP backend is supposed to make unnecessary. The rows
are already crossing the wire at full length and being paid for in tokens, and the trimming that
would have made them readable is a string operation the query could have done at the source.
Concretely, what I wanted was shape-the-output, not filter-the-rows:
Suggested fix
In rough order of how much each one buys:
split(string, delimiter)→ list — the one that unlocks qualified-name handling.substring(string, start [, length])— the general escape hatch; withsizealready presentit covers most truncation without a dedicated function.
replace(original, search, replacement)— commonly paired with the two above.left/right— sugar oversubstring, only if they are cheap.splitalone would cover most of it. If list indexing on asplitresult is not supported by theevaluator,
substringplus the existingsizeis a workable substitute and may be the smallerchange.
Severity
Minor. Nothing here is wrong or misleading — it is a ceiling on what the query language can express,
and the error message makes the ceiling visible immediately rather than letting someone discover it
by trial. Filing it because the fix looks small relative to how often long qualified names come up
in a graph whose primary key is a qualified name.