ID |
|
|---|---|
Status |
Backlog |
Bucket |
architecture |
Priority |
13 |
Theme |
mutations-errors |
Cardinality safety story for UPSERT under the multiRow: regime
R144 inverts the cardinality-safety polarity on DELETE and UPDATE (default
treats every input field as a WHERE filter; PK coverage required;
multiRow: true on @mutation is the opt-out). UPSERT is carved out at
R144’s classify-time rejection because its semantics differ:
INSERT … ON CONFLICT (cols) DO UPDATE SET … requires the
conflict-target columns to form a unique constraint by definition, and one
input row matches at most one existing row. The multiRow: knob does not
apply the same way. This item designs the UPSERT-specific safety story,
lifts R144’s classify-time rejection, and restores UPSERT-generation.
Existing UPSERT fixtures in sakila-example and GraphitronSchemaBuilderTest
migrate as part of this work.
Headline design fork. Under R145 the conflict target is a named
unique key (PK by default; alternative unique key via a @mutation
argument, shape TBD ; candidate: @mutation(typeName: UPSERT,
conflictKey: "alt_unique_index_name"), mirroring the multiRow:
argument shape R144 lands). Cardinality is structurally enforced by SQL
because the conflict target is a unique constraint by definition; no
multiRow: analogue is needed. The @value partition extends
naturally from R144 (the SET-side fields of the UPDATE-arm and the
INSERT-arm values). UPSERT with no @value fields is structurally
"INSERT-or-no-op" and may admit; UPSERT with no filter fields is
rejected as ill-formed (the conflict target must be input-driven).
R145 also lifts R141’s bulk-carrier UPSERT rejection (MutationBulkDmlRecordField
rejects DmlKind.UPSERT at classify time, with a compact-constructor backstop;
see R141’s shipped entry in changelog.md) and adds the UPSERT branch to R141’s
parameterised emitter dispatch. R141 narrowed its admitted-kinds matrix to
{INSERT, UPDATE} to share R144’s UPSERT carve-out before it shipped; R145’s
landing reopens UPSERT on both the direct-DML arm (MutationUpsertTableField)
and R141’s bulk-carrier arm in one pass.