package database import ( "fmt" "gorm.io/gorm" ) // Totals is the single row of running totals in a webhook's event // database. It is what keeps the webhook page's lifetime figures right // after retention has removed the rows they count, and what lets the // page show them without counting every row. // // Storing an event, creating a delivery and failing a delivery each // add one, and retention adds what it deletes to the Removed columns. // Every addition goes through AddTotals, in the transaction that // writes or deletes the rows it counts. type Totals struct { ID int64 `gorm:"primaryKey"` Events int64 `gorm:"not null"` Deliveries int64 `gorm:"not null"` Failures int64 `gorm:"not null"` EventsRemoved int64 `gorm:"not null"` DeliveriesRemoved int64 `gorm:"not null"` FailuresRemoved int64 `gorm:"not null"` } // TableName names the table AddTotals updates. func (Totals) TableName() string { return "totals" } // EventsWithinRetention is how many of the webhook's events are still // stored. func (t Totals) EventsWithinRetention() int64 { return t.Events - t.EventsRemoved } // DeliveriesWithinRetention is how many of the webhook's deliveries // are still stored. func (t Totals) DeliveriesWithinRetention() int64 { return t.Deliveries - t.DeliveriesRemoved } // FailuresWithinRetention is how many of the webhook's failed // deliveries are still stored. func (t Totals) FailuresWithinRetention() int64 { return t.Failures - t.FailuresRemoved } // AddTotals adds each count in add to the webhook's running totals. // Call it on the transaction that writes or deletes the rows it // counts, so the totals change exactly when those rows do. func AddTotals(tx *gorm.DB, add Totals) error { err := tx.Exec( `UPDATE totals SET events = events + ?, deliveries = deliveries + ?, failures = failures + ?, events_removed = events_removed + ?, deliveries_removed = deliveries_removed + ?, failures_removed = failures_removed + ?`, add.Events, add.Deliveries, add.Failures, add.EventsRemoved, add.DeliveriesRemoved, add.FailuresRemoved, ).Error if err != nil { return fmt.Errorf("adding to running totals: %w", err) } return nil }