ID |
|
|---|---|
Status |
Backlog |
Bucket |
Backlog |
Priority |
3 |
Theme |
model-cleanup |
Created |
2026-06-18 |
Updated |
2026-09-08 |
Generated argument extraction is unreadable nested-ternary one-liners
Every generated @condition argument is inlined as a nested ternary directly in the WHERE
chain, e.g. env.getArgument("filter") instanceof Map<?, ?> map1 ? (String) map1.get("brukerId") : null,
repeated once per argument across a single .and(...) term. A method with several condition args
renders as one dense, hard-to-read, hard-to-breakpoint expression (flagged by a consumer as "an
eyesore" that "violates our principle of readable and debuggable code"). R330 made the surrounding
.and(...) chains and the FK-target EXISTS multi-line, but did not touch the per-argument
extraction, which is cross-cutting: it lives in ArgCallEmitter.buildArgExtraction and feeds every
WHERE-emitting site (the QueryConditions shim plus the inline / lookup / split fetcher emitters).
The fix likely extracts each argument into an explicitly-typed named local (never var;
GeneratedSourcesLintTest.emittedSourcesDoNotUseVar bans it in emitted code) before the call, or
routes through a small generated helper, so the call site reads as
Conditions.method(table, brukerId) and each extraction is independently debuggable. Scope:
emitter-only, generated output changes shape but not behaviour; pipeline tests must not assert on
generated method bodies, so coverage stays at the compile/execution tier.
Narrowed for the condition family (2026-07-28, R552 pickup)
R552 (condition-command) absorbs this item’s fix for @condition argument extraction: the glue
body’s one-local-per-argument convention delivers the named-locals shape by construction (R552
slice 1 for the root family, slice 2 for every inline call site), so the ternary chains stop
appearing at condition call sites entirely. Everything below in the expanded scope stays here:
the mutation insert-value ternaries, the polymorphic discriminator expression, and the
$fields-mapper deep-path extraction with its inputs/*.fromMap reuse finding are not condition
content and remain this item’s. Do not delete this item when R552 closes.
Expanded scope (2026-07-24 audit)
A full audit of the graphitron-sakila-example generated tree found the same
expression-over-statement pattern beyond @condition extraction; this item now covers all of it
(same emitter family, same fix shape: hoist to explicitly-typed named locals per path segment,
named after the GraphQL argument or column):
-
Deep input-path extraction in fetchers and
$fieldsmappers: nestedinstanceof Map/Listternary chains up to ~600 characters on one line (QueryFetchers.filmsByNestedListPath, the two ~330-char.where(...)arguments inoccupantsByFilter,types/Store.$fieldsGrouped). Some sites re-check the sameinstanceoftwice or testin != nullafterin.get(...)was already dereferenced; the locals-first rewrite removes the redundancy. Note the emitter already generates typedinputs/*.fromMapclasses for many of these shapes and then ignores them, re-digging raw maps at the use site; reusing the input classes where one exists deletes the pattern outright. -
Insert-value ternaries:
in.containsKey("x") ? DSL.val(...) : DSL.defaultValue(...)emitted once per column per mutation (39 occurrences inMutationFetchers). A named local per column, or a tiny emittedvalOrDefault(in, "x", FIELD)helper, restores the column list’s readability. -
The polymorphic discriminator expression
DSL.field(table.getQualifiedName().append(DSL.name("content_type")), Object.class)is rebuilt inline up to four times within a single method (29 occurrences across the root fetcher classes); bind it once to a named local per method.
R521 (generated-output-hygiene-sweep) tracks the complementary naming/dedup/hygiene findings
from the same audit and explicitly excludes statement-form defects in favour of this item.
The descent is now safe to splice, and that does not discharge this item (2026-09-08)
The nested-map descent that reads a wire value (WireMapChain.of, and the presence-test sibling
TypeFetcherGenerator.nestedContainsKeyExpr) now returns a primary expression: parenthesised at
the producer, so a caller may splice it into any operand slot. That closed a correctness defect,
not a readability one: before it, splicing the descent into an instanceof pattern test or a
== null comparison emitted Java javac rejects, and the mutation DML decode-locals walks did
exactly that at six emit statements. The fix is one paren pair, deliberately chosen over the
statement-form migration so a shipped consumer blocker did not ride on a rewrite of those methods.
So the ternaries this item is about are unchanged in shape, and the expanded scope above still
names them. What changed is that they are no longer a trap for the next caller. The statement-form
end state remains this item’s: routing the mutation DML sites through
ArgPathHelperRegistry collapses each call site to a method invocation (a primary expression by
construction) and turns the descent into readable statements in a private static helper, which also
discharges the "statement form over expression tricks" and the throwaway-pattern-variable naming
rule that the _s-prefixed decode locals violate today. It was deferred there because
TypeFetcherGenerator’s mutation walk is a chain of `private static methods that would each grow
a registry parameter, which is a signature sweep rather than a fix. When that lands, the paren pair
becomes redundant at those sites and can go with them; it stays load-bearing for every other
consumer of the descent until then.
R85 (helper-emission-non-fetcher-hosts) reshapes the same method: it fixes the
ContextArg arm of ArgCallEmitter.buildArgExtraction that fails to emit the
graphitronContext helper on non-fetcher hosts, while this item extracts the
per-argument extraction into named locals or a helper for readability. Whichever
lands first changes the other’s diff; sequence knowingly (distinct deliverables,
not a merge).