The redemption arm (method = REDEMPTION) of the transaction UNION, as a
view. Two sub-arms: the initiating debit and the void/return credit.
Same motivation as depositTransactionView (see schema/deposit.ts): the
inline 12-arm UNION serialises past the RDS Proxy's 16KB parse limit and
pins the client's database connection for the rest of the session. Behind a
view the runtime statement is a short SELECT.
NOT MATERIALIZED on t is deliberate: the caller's filters are outer
predicates on this view's projected columns, and only an inlined CTE lets
them reach redemption's indexes (idx_redemption_initiate_tx_id,
idx_redemption_void_tx_id, redemption_customer_id_*).
The caller-supplied filters live in
transaction-services/queries/redemption.ts as predicates on this view's own
projected columns, because a view takes no parameters. They are plain
contract-column comparisons emitted by the shared
transactionScalarConditions, so what matters here is what each filtered
column projects:
customer_id — customer.external_id, resolved inside t and projected
unchanged by both sub-arms.
signature — t.initiate_tx_id on the debit sub-arm, t.void_tx_id on
the void sub-arm. One predicate covers both.
bank_id — bank_transaction.bank_id, resolved inside t and projected
by both sub-arms. bank_transaction is LEFT JOINed, so a NULL bank_id
fails IN (...).
The two redemption_data guards in t are business logic, not filters: they
exclude ACH-batched and withdrawal-backed redemptions, which belong to other
arms. They stay.
Entity resolution is already local to this arm and unchanged: a redemption
has no per-row identity / sub-organization, so the entity is the customer's
root organization, resolved by the organization LEFT JOIN in t. The arm
still projects external_organization_id so the outer enrichment's
o_customer fallback (and the UNION shape shared with the still-raw arms)
is unaffected.
securityInvoker is required, not cosmetic — every underlying table has RLS
enabled, and without it the view would run with the owner's row visibility
and silently bypass the querying role's policies.
The redemption arm (method =
REDEMPTION) of the transaction UNION, as a view. Two sub-arms: the initiating debit and the void/return credit.Same motivation as
depositTransactionView(seeschema/deposit.ts): the inline 12-arm UNION serialises past the RDS Proxy's 16KB parse limit and pins the client's database connection for the rest of the session. Behind a view the runtime statement is a short SELECT.NOT MATERIALIZEDontis deliberate: the caller's filters are outer predicates on this view's projected columns, and only an inlined CTE lets them reachredemption's indexes (idx_redemption_initiate_tx_id,idx_redemption_void_tx_id,redemption_customer_id_*).The caller-supplied filters live in
transaction-services/queries/redemption.tsas predicates on this view's own projected columns, because a view takes no parameters. They are plain contract-column comparisons emitted by the sharedtransactionScalarConditions, so what matters here is what each filtered column projects:customer_id—customer.external_id, resolved insidetand projected unchanged by both sub-arms.signature—t.initiate_tx_idon the debit sub-arm,t.void_tx_idon the void sub-arm. One predicate covers both.bank_id—bank_transaction.bank_id, resolved insidetand projected by both sub-arms.bank_transactionis LEFT JOINed, so a NULLbank_idfailsIN (...).The two
redemption_dataguards intare business logic, not filters: they exclude ACH-batched and withdrawal-backed redemptions, which belong to other arms. They stay.Entity resolution is already local to this arm and unchanged: a redemption has no per-row identity / sub-organization, so the entity is the customer's root organization, resolved by the
organizationLEFT JOIN int. The arm still projectsexternal_organization_idso the outer enrichment'so_customerfallback (and the UNION shape shared with the still-raw arms) is unaffected.securityInvokeris required, not cosmetic — every underlying table has RLS enabled, and without it the view would run with the owner's row visibility and silently bypass the querying role's policies.