Identifies the static Java method that extracts the parent-side join-key tuple when the parent is a @record-backed DTO with no FK metadata in the jOOQ catalog. Applies when the parent’s backing class is a plain Java record / POJO (not a jOOQ Record / TableRecord); the lifter extracts the key value(s) from the parent instance, the rewrite matches the lifted RowN against the columns the field’s first JOIN ON predicate consumes on the parent side, and a column-keyed DataLoader drives the batch.
@sourceRow composes with @reference for multi-hop paths from a DTO parent. Without @reference, the lifter’s RowN matches the leaf target table’s primary key columns directly.
Pairs with @record(record:) supplying the parent class. The directive is rejected on @table parents (use @reference there) and on jOOQ-record parents (the catalog already supplies the path).
SDL signature
directive @sourceRow(
className: String!
method: String!
) on FIELD_DEFINITION
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
|
|
(required) |
Fully-qualified Java class name carrying the static lifter method. Must be on the rewrite plugin’s classpath. |
|
|
(required) |
Static method name on |
@sourceRow uses flat (className, method) args rather than the ExternalCodeReference wrapper used by @service and the other reflection-driven directives. Sibling directives are documented in How-to: Wire external Java code; the dedicated walk-through for @sourceRow lives in How-to: Source-row directive.
Composition with @reference
Two derivations, no third case:
-
With
@reference. The lifter’sRowNmatches the first FK hop’s source-side columns. Subsequent hops walk the catalog FK chain from there to the leaf target. The classifier producesBatchKey.LifterPathKeyed. -
Without
@reference. The lifter’sRowNmatches the leaf target table’s primary key columns. The single column-equality JOIN folds source-side and target-side onto the same columns. The classifier producesBatchKey.LifterLeafKeyed.
The arity / column-class match is checked at build time against the derived parent-side tuple. A mismatch fails the build; the diagnostic message names the offending position, the lifter’s actual type, and the expected column (with two distinct phrasings for the two cases so the user-facing text reflects which derivation was applied).
Canonical examples
Leaf-PK case (no @reference). The DTO carries the leaf table’s primary-key value and the lifter returns it directly:
type CreateFilmPayload @record(record: {className: "no.sikt.graphitron.rewrite.test.services.CreateFilmPayload"}) {
languageId: Int!
language: [Language!]!
@sourceRow(
className: "no.sikt.graphitron.rewrite.test.services.CreateFilmPayloadLifter",
method: "liftLanguageId"
)
}
Path-keyed case (@reference-composed). The DTO carries a key the catalog can navigate from, and @reference walks the FK chain to the leaf:
type CustomerAddressSummary @record(record: {className: "no.sikt.graphitron.rewrite.test.services.CustomerAddressSummary"}) {
customerId: Int!
address: [Address!]!
@sourceRow(
className: "no.sikt.graphitron.rewrite.test.services.CustomerAddressSummaryLifter",
method: "addressIdOf"
)
@reference(path: [{key: "customer_address_id_fkey"}])
}
The Java side for the leaf-PK lifter:
public final class CreateFilmPayloadLifter {
public static Row1<Integer> liftLanguageId(CreateFilmPayload p) {
return DSL.row(p.languageId());
}
}
Per request the framework collects every parent, calls the lifter once per parent, gathers the resulting RowN keys, and dispatches a single batch keyed on those values. Each parent receives the matching leaf row(s) at scatter time.
Constraints
-
Required when a field on a non-table-backed
@recordparent returns a@tabletype and would otherwise be rejected asRecordTableField (or RecordLookupTableField) requires a FK join path and a typed backing class for batch key extraction. -
The parent’s
@record(record: {className: …})must declare a backing class. The directive is rejected on bare@recordparents with no class. -
Rejected on
@tableparents; there’s no DTO to lift from. Use@referencefor catalog-driven joins instead. -
Rejected on jOOQ-record parents (
JooqTableRecordType/JooqRecordType); the catalog record already drives batching, and a typed accessor or jOOQ-record FK supplies the key. -
The lifter’s
RowNarity must equal the derived parent-side tuple size:path.first().sourceSideColumns()when@referenceis present, ortargetTable.primaryKeyColumns()otherwise. -
Per-position Java types of the
RowNarguments must equal the corresponding derived column’s Java class. Wildcards (Row1<? extends Number>) are rejected at build time. -
Rejected on
@asConnectionfields. -
@referenceparse failures (unknown FK key, broken connectivity) surface directly, without the resolver double-validating the lifter’s signature against an unresolvable path.
See also
-
@recordis the parent-side directive that decides whether@sourceRowis needed: jOOQ-backed@recordtypes skip it; plain-Java-record / POJO types reach for it. -
@referenceis the catalog-driven counterpart on@tableparents and the composition target for multi-hop@sourceRowpaths. -
How-to: Source-row directive walks two end-to-end examples.
-
How-to: Result-type variants covers
JavaRecordTypeparents, accessor inference, and when to reach for@sourceRow.