check / check (push) Waiting to run
Replaces #559, which conflicted. Model: opus-5-5
137 lines
4.2 KiB
Go
137 lines
4.2 KiB
Go
package database
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// The running totals in a webhook's event database keep the webhook
|
|
// page's lifetime figures right after retention has removed the rows
|
|
// they count, and let the page show them without counting every row.
|
|
// Each total changes in the transaction that writes or deletes the
|
|
// rows it counts.
|
|
|
|
// EventTotals is the single row counting a webhook's events: every
|
|
// event ever stored, how many of them retention has deleted, and when
|
|
// the newest arrived, which retention leaves as it is.
|
|
type EventTotals struct {
|
|
ID int64 `gorm:"primaryKey"`
|
|
|
|
Events int64 `gorm:"not null"`
|
|
EventsRemoved int64 `gorm:"not null"`
|
|
|
|
// LastEventAt is when the newest event arrived, or nil before the
|
|
// first.
|
|
LastEventAt *time.Time
|
|
}
|
|
|
|
// TableName names the table AddEventTotals updates.
|
|
func (EventTotals) TableName() string {
|
|
return "event_totals"
|
|
}
|
|
|
|
// TargetTotals is one row per target counting its deliveries: every
|
|
// delivery ever created, how many became delivered and how many
|
|
// failed, and how many deliveries and failed deliveries retention has
|
|
// deleted. The webhook's delivery figures are these rows summed.
|
|
type TargetTotals struct {
|
|
TargetID string `gorm:"type:uuid;primaryKey"`
|
|
|
|
Deliveries int64 `gorm:"not null"`
|
|
Delivered int64 `gorm:"not null"`
|
|
Failed int64 `gorm:"not null"`
|
|
|
|
DeliveriesRemoved int64 `gorm:"not null"`
|
|
FailedRemoved int64 `gorm:"not null"`
|
|
}
|
|
|
|
// TableName names the table AddTargetTotals updates.
|
|
func (TargetTotals) TableName() string {
|
|
return "target_totals"
|
|
}
|
|
|
|
// EntrypointTotals is one row per entrypoint, created by the first
|
|
// event that arrives on its URL: when the newest such event arrived,
|
|
// which retention leaves as it is. A resubmitted copy did not arrive
|
|
// on the URL and does not change it.
|
|
type EntrypointTotals struct {
|
|
EntrypointID string `gorm:"type:uuid;primaryKey"`
|
|
|
|
LastEventAt time.Time `gorm:"not null"`
|
|
}
|
|
|
|
// TableName names the table AddEntrypointTotals updates.
|
|
func (EntrypointTotals) TableName() string {
|
|
return "entrypoint_totals"
|
|
}
|
|
|
|
// AddEventTotals adds each count in add to the webhook's event totals,
|
|
// and records add.LastEventAt as when the newest event arrived if it is
|
|
// set. Call it on the transaction that writes or deletes the events it
|
|
// counts.
|
|
func AddEventTotals(tx *gorm.DB, add EventTotals) error {
|
|
err := tx.Exec(
|
|
`UPDATE event_totals SET
|
|
events = events + ?,
|
|
events_removed = events_removed + ?,
|
|
last_event_at = coalesce(?, last_event_at)`,
|
|
add.Events, add.EventsRemoved, add.LastEventAt,
|
|
).Error
|
|
if err != nil {
|
|
return fmt.Errorf("adding to event totals: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// AddTargetTotals adds each count in add to the totals of the target
|
|
// add.TargetID names, creating its row the first time. Call it on the
|
|
// transaction that writes or deletes the deliveries it counts.
|
|
func AddTargetTotals(tx *gorm.DB, add TargetTotals) error {
|
|
err := tx.Exec(
|
|
`INSERT INTO target_totals (target_id, deliveries, delivered,
|
|
failed, deliveries_removed, failed_removed)
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT (target_id) DO UPDATE SET
|
|
deliveries = deliveries + excluded.deliveries,
|
|
delivered = delivered + excluded.delivered,
|
|
failed = failed + excluded.failed,
|
|
deliveries_removed =
|
|
deliveries_removed + excluded.deliveries_removed,
|
|
failed_removed = failed_removed + excluded.failed_removed`,
|
|
add.TargetID, add.Deliveries, add.Delivered,
|
|
add.Failed, add.DeliveriesRemoved, add.FailedRemoved,
|
|
).Error
|
|
if err != nil {
|
|
return fmt.Errorf(
|
|
"adding to totals of target %s: %w", add.TargetID, err,
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// AddEntrypointTotals records add.LastEventAt as when the newest event
|
|
// arrived on the URL of the entrypoint add.EntrypointID names, creating
|
|
// its row the first time. Call it on the transaction that stores the
|
|
// event.
|
|
func AddEntrypointTotals(tx *gorm.DB, add EntrypointTotals) error {
|
|
err := tx.Exec(
|
|
`INSERT INTO entrypoint_totals (entrypoint_id, last_event_at)
|
|
VALUES (?, ?)
|
|
ON CONFLICT (entrypoint_id) DO UPDATE SET
|
|
last_event_at = excluded.last_event_at`,
|
|
add.EntrypointID, add.LastEventAt,
|
|
).Error
|
|
if err != nil {
|
|
return fmt.Errorf(
|
|
"adding to totals of entrypoint %s: %w",
|
|
add.EntrypointID, err,
|
|
)
|
|
}
|
|
|
|
return nil
|
|
}
|