The card arm of the transaction search, as a view.
Same motivation as depositTransactionView: the 12-arm transaction UNION
serialises to ~124KB inline, and RDS Proxy pins a client session to its
database connection for any statement over 16KB. Behind a view the runtime
statement is a short SELECT.
The cardholder/issuer split is structural, enforced by the FROM-clause INNER
JOINs: cardholder arms require the card's girasol_account_id, issuer arms
require the transaction's settlement_wallet_id. Each card transaction has
separate rows for the cardholder customer and Girasol, so each side only
matches its own JOIN.
The caller-supplied filters live in transaction-services/queries/card.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 — the cardholder customer's external id on sub-arms 1-2,
issuer_customer.external_id on sub-arms 3-4.
signature — the receipt id on sub-arms 1 and 3, the clearing receipt id
on sub-arms 2 and 4. Both CTEs are NOT MATERIALIZED so the predicate still
reaches idx_girasol_card_txn_receipt_id /
idx_girasol_card_txn_clearing_receipt_id.
This arm has no bank id filter — card rows project a NULL bank_id and the
caller skips the arm entirely when bank ids are set.
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 card arm of the transaction search, as a view.
Same motivation as
depositTransactionView: the 12-arm transaction UNION serialises to ~124KB inline, and RDS Proxy pins a client session to its database connection for any statement over 16KB. Behind a view the runtime statement is a short SELECT.Four sub-arms, two audiences x two event shapes:
The cardholder/issuer split is structural, enforced by the FROM-clause INNER JOINs: cardholder arms require the card's girasol_account_id, issuer arms require the transaction's settlement_wallet_id. Each card transaction has separate rows for the cardholder customer and Girasol, so each side only matches its own JOIN.
The caller-supplied filters live in
transaction-services/queries/card.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— the cardholder customer's external id on sub-arms 1-2,issuer_customer.external_idon sub-arms 3-4.signature— the receipt id on sub-arms 1 and 3, the clearing receipt id on sub-arms 2 and 4. Both CTEs are NOT MATERIALIZED so the predicate still reaches idx_girasol_card_txn_receipt_id / idx_girasol_card_txn_clearing_receipt_id.This arm has no bank id filter — card rows project a NULL bank_id and the caller skips the arm entirely when bank ids are set.
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.