diff --git a/sqldb/sqlc/invoices.sql.go b/sqldb/sqlc/invoices.sql.go index 178e70d49..d9d57cae7 100644 --- a/sqldb/sqlc/invoices.sql.go +++ b/sqldb/sqlc/invoices.sql.go @@ -64,15 +64,74 @@ func (q *Queries) DeleteInvoice(ctx context.Context, arg DeleteInvoiceParams) (s ) } +const fetchPendingInvoices = `-- name: FetchPendingInvoices :many +SELECT + invoices.id, invoices.hash, invoices.preimage, invoices.settle_index, invoices.settled_at, invoices.memo, invoices.amount_msat, invoices.cltv_delta, invoices.expiry, invoices.payment_addr, invoices.payment_request, invoices.payment_request_hash, invoices.state, invoices.amount_paid_msat, invoices.is_amp, invoices.is_hodl, invoices.is_keysend, invoices.created_at +FROM invoices +WHERE state IN (0, 3) -- 0 = ContractOpen, 3 = ContractAccepted +ORDER BY id ASC +LIMIT $2 OFFSET $1 +` + +type FetchPendingInvoicesParams struct { + NumOffset int32 + NumLimit int32 +} + +// FetchPendingInvoices returns all invoices in a pending state (open or +// accepted). The invoices_state_idx index on the state column makes this a +// fast index scan rather than a full table scan. +func (q *Queries) FetchPendingInvoices(ctx context.Context, arg FetchPendingInvoicesParams) ([]Invoice, error) { + rows, err := q.db.QueryContext(ctx, fetchPendingInvoices, arg.NumOffset, arg.NumLimit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Invoice + for rows.Next() { + var i Invoice + if err := rows.Scan( + &i.ID, + &i.Hash, + &i.Preimage, + &i.SettleIndex, + &i.SettledAt, + &i.Memo, + &i.AmountMsat, + &i.CltvDelta, + &i.Expiry, + &i.PaymentAddr, + &i.PaymentRequest, + &i.PaymentRequestHash, + &i.State, + &i.AmountPaidMsat, + &i.IsAmp, + &i.IsHodl, + &i.IsKeysend, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const filterInvoices = `-- name: FilterInvoices :many SELECT invoices.id, invoices.hash, invoices.preimage, invoices.settle_index, invoices.settled_at, invoices.memo, invoices.amount_msat, invoices.cltv_delta, invoices.expiry, invoices.payment_addr, invoices.payment_request, invoices.payment_request_hash, invoices.state, invoices.amount_paid_msat, invoices.is_amp, invoices.is_hodl, invoices.is_keysend, invoices.created_at FROM invoices WHERE ( - id >= $1 OR + id >= $1 OR $1 IS NULL ) AND ( - id <= $2 OR + id <= $2 OR $2 IS NULL ) AND ( settle_index >= $3 OR @@ -81,18 +140,18 @@ WHERE ( settle_index <= $4 OR $4 IS NULL ) AND ( - state = $5 OR + state = $5 OR $5 IS NULL ) AND ( created_at >= $6 OR $6 IS NULL ) AND ( - created_at < $7 OR + created_at < $7 OR $7 IS NULL ) AND ( CASE WHEN $8 = TRUE THEN (state = 0 OR state = 3) - ELSE TRUE + ELSE TRUE END ) ORDER BY @@ -175,6 +234,279 @@ func (q *Queries) FilterInvoices(ctx context.Context, arg FilterInvoicesParams) return items, nil } +const filterInvoicesByAddIndex = `-- name: FilterInvoicesByAddIndex :many +SELECT + invoices.id, invoices.hash, invoices.preimage, invoices.settle_index, invoices.settled_at, invoices.memo, invoices.amount_msat, invoices.cltv_delta, invoices.expiry, invoices.payment_addr, invoices.payment_request, invoices.payment_request_hash, invoices.state, invoices.amount_paid_msat, invoices.is_amp, invoices.is_hodl, invoices.is_keysend, invoices.created_at +FROM invoices +WHERE id >= $1 +ORDER BY id ASC +LIMIT $3 OFFSET $2 +` + +type FilterInvoicesByAddIndexParams struct { + AddIndexGet int64 + NumOffset int32 + NumLimit int32 +} + +// FilterInvoicesByAddIndex returns invoices whose add_index (primary key id) +// is greater than or equal to the given value, ordered by id. Because id is +// the primary key, this is always an efficient range scan on the clustered +// index. +func (q *Queries) FilterInvoicesByAddIndex(ctx context.Context, arg FilterInvoicesByAddIndexParams) ([]Invoice, error) { + rows, err := q.db.QueryContext(ctx, filterInvoicesByAddIndex, arg.AddIndexGet, arg.NumOffset, arg.NumLimit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Invoice + for rows.Next() { + var i Invoice + if err := rows.Scan( + &i.ID, + &i.Hash, + &i.Preimage, + &i.SettleIndex, + &i.SettledAt, + &i.Memo, + &i.AmountMsat, + &i.CltvDelta, + &i.Expiry, + &i.PaymentAddr, + &i.PaymentRequest, + &i.PaymentRequestHash, + &i.State, + &i.AmountPaidMsat, + &i.IsAmp, + &i.IsHodl, + &i.IsKeysend, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const filterInvoicesBySettleIndex = `-- name: FilterInvoicesBySettleIndex :many +SELECT + invoices.id, invoices.hash, invoices.preimage, invoices.settle_index, invoices.settled_at, invoices.memo, invoices.amount_msat, invoices.cltv_delta, invoices.expiry, invoices.payment_addr, invoices.payment_request, invoices.payment_request_hash, invoices.state, invoices.amount_paid_msat, invoices.is_amp, invoices.is_hodl, invoices.is_keysend, invoices.created_at +FROM invoices +WHERE settle_index >= $1 +ORDER BY id ASC +LIMIT $3 OFFSET $2 +` + +type FilterInvoicesBySettleIndexParams struct { + SettleIndexGet sql.NullInt64 + NumOffset int32 + NumLimit int32 +} + +// FilterInvoicesBySettleIndex returns settled invoices whose settle_index is +// greater than or equal to the given value, ordered by id. The caller must +// always supply a concrete lower bound so the invoices_settle_index_idx index +// can be used. +func (q *Queries) FilterInvoicesBySettleIndex(ctx context.Context, arg FilterInvoicesBySettleIndexParams) ([]Invoice, error) { + rows, err := q.db.QueryContext(ctx, filterInvoicesBySettleIndex, arg.SettleIndexGet, arg.NumOffset, arg.NumLimit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Invoice + for rows.Next() { + var i Invoice + if err := rows.Scan( + &i.ID, + &i.Hash, + &i.Preimage, + &i.SettleIndex, + &i.SettledAt, + &i.Memo, + &i.AmountMsat, + &i.CltvDelta, + &i.Expiry, + &i.PaymentAddr, + &i.PaymentRequest, + &i.PaymentRequestHash, + &i.State, + &i.AmountPaidMsat, + &i.IsAmp, + &i.IsHodl, + &i.IsKeysend, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const filterInvoicesForward = `-- name: FilterInvoicesForward :many +SELECT + invoices.id, invoices.hash, invoices.preimage, invoices.settle_index, invoices.settled_at, invoices.memo, invoices.amount_msat, invoices.cltv_delta, invoices.expiry, invoices.payment_addr, invoices.payment_request, invoices.payment_request_hash, invoices.state, invoices.amount_paid_msat, invoices.is_amp, invoices.is_hodl, invoices.is_keysend, invoices.created_at +FROM invoices +WHERE id >= $1 + AND (NOT $2 OR state IN (0, 3)) -- 0 = ContractOpen, 3 = ContractAccepted + AND created_at >= $3 + AND created_at < $4 +ORDER BY id ASC +LIMIT $6 OFFSET $5 +` + +type FilterInvoicesForwardParams struct { + AddIndexGet int64 + PendingOnly interface{} + CreatedAfter time.Time + CreatedBefore time.Time + NumOffset int32 + NumLimit int32 +} + +// FilterInvoicesForward returns invoices in ascending id order starting from +// add_index_get. All parameters are non-nullable so the planner always sees +// plain range predicates and can use the primary-key index. The caller is +// responsible for supplying Go-side defaults when a filter is not needed: +// +// created_after → time.Unix(0, 0).UTC() (epoch – before any invoice) +// created_before → time.Date(9999, …) (far future – no upper cap) +// pending_only → false (include all states) +func (q *Queries) FilterInvoicesForward(ctx context.Context, arg FilterInvoicesForwardParams) ([]Invoice, error) { + rows, err := q.db.QueryContext(ctx, filterInvoicesForward, + arg.AddIndexGet, + arg.PendingOnly, + arg.CreatedAfter, + arg.CreatedBefore, + arg.NumOffset, + arg.NumLimit, + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Invoice + for rows.Next() { + var i Invoice + if err := rows.Scan( + &i.ID, + &i.Hash, + &i.Preimage, + &i.SettleIndex, + &i.SettledAt, + &i.Memo, + &i.AmountMsat, + &i.CltvDelta, + &i.Expiry, + &i.PaymentAddr, + &i.PaymentRequest, + &i.PaymentRequestHash, + &i.State, + &i.AmountPaidMsat, + &i.IsAmp, + &i.IsHodl, + &i.IsKeysend, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const filterInvoicesReverse = `-- name: FilterInvoicesReverse :many +SELECT + invoices.id, invoices.hash, invoices.preimage, invoices.settle_index, invoices.settled_at, invoices.memo, invoices.amount_msat, invoices.cltv_delta, invoices.expiry, invoices.payment_addr, invoices.payment_request, invoices.payment_request_hash, invoices.state, invoices.amount_paid_msat, invoices.is_amp, invoices.is_hodl, invoices.is_keysend, invoices.created_at +FROM invoices +WHERE id <= $1 + AND (NOT $2 OR state IN (0, 3)) -- 0 = ContractOpen, 3 = ContractAccepted + AND created_at >= $3 + AND created_at < $4 +ORDER BY id DESC +LIMIT $6 OFFSET $5 +` + +type FilterInvoicesReverseParams struct { + AddIndexLet int64 + PendingOnly interface{} + CreatedAfter time.Time + CreatedBefore time.Time + NumOffset int32 + NumLimit int32 +} + +// FilterInvoicesReverse is the descending counterpart of FilterInvoicesForward. +// It returns invoices in descending id order up to and including add_index_let. +// See FilterInvoicesForward for the expected Go-side defaults. +func (q *Queries) FilterInvoicesReverse(ctx context.Context, arg FilterInvoicesReverseParams) ([]Invoice, error) { + rows, err := q.db.QueryContext(ctx, filterInvoicesReverse, + arg.AddIndexLet, + arg.PendingOnly, + arg.CreatedAfter, + arg.CreatedBefore, + arg.NumOffset, + arg.NumLimit, + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Invoice + for rows.Next() { + var i Invoice + if err := rows.Scan( + &i.ID, + &i.Hash, + &i.Preimage, + &i.SettleIndex, + &i.SettledAt, + &i.Memo, + &i.AmountMsat, + &i.CltvDelta, + &i.Expiry, + &i.PaymentAddr, + &i.PaymentRequest, + &i.PaymentRequestHash, + &i.State, + &i.AmountPaidMsat, + &i.IsAmp, + &i.IsHodl, + &i.IsKeysend, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const getInvoice = `-- name: GetInvoice :many SELECT i.id, i.hash, i.preimage, i.settle_index, i.settled_at, i.memo, i.amount_msat, i.cltv_delta, i.expiry, i.payment_addr, i.payment_request, i.payment_request_hash, i.state, i.amount_paid_msat, i.is_amp, i.is_hodl, i.is_keysend, i.created_at diff --git a/sqldb/sqlc/querier.go b/sqldb/sqlc/querier.go index d26f845d0..6e0011a7d 100644 --- a/sqldb/sqlc/querier.go +++ b/sqldb/sqlc/querier.go @@ -31,8 +31,34 @@ type Querier interface { DeleteZombieChannel(ctx context.Context, arg DeleteZombieChannelParams) (sql.Result, error) FetchAMPSubInvoiceHTLCs(ctx context.Context, arg FetchAMPSubInvoiceHTLCsParams) ([]FetchAMPSubInvoiceHTLCsRow, error) FetchAMPSubInvoices(ctx context.Context, arg FetchAMPSubInvoicesParams) ([]AmpSubInvoice, error) + // FetchPendingInvoices returns all invoices in a pending state (open or + // accepted). The invoices_state_idx index on the state column makes this a + // fast index scan rather than a full table scan. + FetchPendingInvoices(ctx context.Context, arg FetchPendingInvoicesParams) ([]Invoice, error) FetchSettledAMPSubInvoices(ctx context.Context, arg FetchSettledAMPSubInvoicesParams) ([]FetchSettledAMPSubInvoicesRow, error) FilterInvoices(ctx context.Context, arg FilterInvoicesParams) ([]Invoice, error) + // FilterInvoicesByAddIndex returns invoices whose add_index (primary key id) + // is greater than or equal to the given value, ordered by id. Because id is + // the primary key, this is always an efficient range scan on the clustered + // index. + FilterInvoicesByAddIndex(ctx context.Context, arg FilterInvoicesByAddIndexParams) ([]Invoice, error) + // FilterInvoicesBySettleIndex returns settled invoices whose settle_index is + // greater than or equal to the given value, ordered by id. The caller must + // always supply a concrete lower bound so the invoices_settle_index_idx index + // can be used. + FilterInvoicesBySettleIndex(ctx context.Context, arg FilterInvoicesBySettleIndexParams) ([]Invoice, error) + // FilterInvoicesForward returns invoices in ascending id order starting from + // add_index_get. All parameters are non-nullable so the planner always sees + // plain range predicates and can use the primary-key index. The caller is + // responsible for supplying Go-side defaults when a filter is not needed: + // created_after → time.Unix(0, 0).UTC() (epoch – before any invoice) + // created_before → time.Date(9999, …) (far future – no upper cap) + // pending_only → false (include all states) + FilterInvoicesForward(ctx context.Context, arg FilterInvoicesForwardParams) ([]Invoice, error) + // FilterInvoicesReverse is the descending counterpart of FilterInvoicesForward. + // It returns invoices in descending id order up to and including add_index_let. + // See FilterInvoicesForward for the expected Go-side defaults. + FilterInvoicesReverse(ctx context.Context, arg FilterInvoicesReverseParams) ([]Invoice, error) GetAMPInvoiceID(ctx context.Context, setID []byte) (int64, error) GetChannelAndNodesBySCID(ctx context.Context, arg GetChannelAndNodesBySCIDParams) (GetChannelAndNodesBySCIDRow, error) GetChannelByOutpointWithPolicies(ctx context.Context, arg GetChannelByOutpointWithPoliciesParams) (GetChannelByOutpointWithPoliciesRow, error) diff --git a/sqldb/sqlc/queries/invoices.sql b/sqldb/sqlc/queries/invoices.sql index db1f46e61..ff23a6cf0 100644 --- a/sqldb/sqlc/queries/invoices.sql +++ b/sqldb/sqlc/queries/invoices.sql @@ -65,15 +65,82 @@ FROM invoices i INNER JOIN amp_sub_invoices a ON i.id = a.invoice_id AND a.set_id = $1; +-- name: FetchPendingInvoices :many +-- FetchPendingInvoices returns all invoices in a pending state (open or +-- accepted). The invoices_state_idx index on the state column makes this a +-- fast index scan rather than a full table scan. +SELECT + invoices.* +FROM invoices +WHERE state IN (0, 3) -- 0 = ContractOpen, 3 = ContractAccepted +ORDER BY id ASC +LIMIT @num_limit OFFSET @num_offset; + +-- name: FilterInvoicesBySettleIndex :many +-- FilterInvoicesBySettleIndex returns settled invoices whose settle_index is +-- greater than or equal to the given value, ordered by id. The caller must +-- always supply a concrete lower bound so the invoices_settle_index_idx index +-- can be used. +SELECT + invoices.* +FROM invoices +WHERE settle_index >= @settle_index_get +ORDER BY id ASC +LIMIT @num_limit OFFSET @num_offset; + +-- name: FilterInvoicesByAddIndex :many +-- FilterInvoicesByAddIndex returns invoices whose add_index (primary key id) +-- is greater than or equal to the given value, ordered by id. Because id is +-- the primary key, this is always an efficient range scan on the clustered +-- index. +SELECT + invoices.* +FROM invoices +WHERE id >= @add_index_get +ORDER BY id ASC +LIMIT @num_limit OFFSET @num_offset; + +-- name: FilterInvoicesForward :many +-- FilterInvoicesForward returns invoices in ascending id order starting from +-- add_index_get. All parameters are non-nullable so the planner always sees +-- plain range predicates and can use the primary-key index. The caller is +-- responsible for supplying Go-side defaults when a filter is not needed: +-- created_after → time.Unix(0, 0).UTC() (epoch – before any invoice) +-- created_before → time.Date(9999, …) (far future – no upper cap) +-- pending_only → false (include all states) +SELECT + invoices.* +FROM invoices +WHERE id >= @add_index_get + AND (NOT @pending_only OR state IN (0, 3)) -- 0 = ContractOpen, 3 = ContractAccepted + AND created_at >= @created_after + AND created_at < @created_before +ORDER BY id ASC +LIMIT @num_limit OFFSET @num_offset; + +-- name: FilterInvoicesReverse :many +-- FilterInvoicesReverse is the descending counterpart of FilterInvoicesForward. +-- It returns invoices in descending id order up to and including add_index_let. +-- See FilterInvoicesForward for the expected Go-side defaults. +SELECT + invoices.* +FROM invoices +WHERE id <= @add_index_let + AND (NOT @pending_only OR state IN (0, 3)) -- 0 = ContractOpen, 3 = ContractAccepted + AND created_at >= @created_after + AND created_at < @created_before +ORDER BY id DESC +LIMIT @num_limit OFFSET @num_offset; + -- name: FilterInvoices :many SELECT invoices.* FROM invoices WHERE ( - id >= sqlc.narg('add_index_get') OR + id >= sqlc.narg('add_index_get') OR sqlc.narg('add_index_get') IS NULL ) AND ( - id <= sqlc.narg('add_index_let') OR + id <= sqlc.narg('add_index_let') OR sqlc.narg('add_index_let') IS NULL ) AND ( settle_index >= sqlc.narg('settle_index_get') OR @@ -82,18 +149,18 @@ WHERE ( settle_index <= sqlc.narg('settle_index_let') OR sqlc.narg('settle_index_let') IS NULL ) AND ( - state = sqlc.narg('state') OR + state = sqlc.narg('state') OR sqlc.narg('state') IS NULL ) AND ( created_at >= sqlc.narg('created_after') OR sqlc.narg('created_after') IS NULL ) AND ( - created_at < sqlc.narg('created_before') OR + created_at < sqlc.narg('created_before') OR sqlc.narg('created_before') IS NULL ) AND ( CASE WHEN sqlc.narg('pending_only') = TRUE THEN (state = 0 OR state = 3) - ELSE TRUE + ELSE TRUE END ) ORDER BY