check / check (push) Successful in 3m4s
The per-webhook event databases had no secondary indexes, so startup recovery, the retry and pending sweeps, the queue-depth sampler, the event log and retention each read whole tables. Indexes declared in the GORM model tags now serve them, and AutoMigrate adds them to new and existing databases alike. Each index also covers deleted_at: GORM adds deleted_at IS NULL to these queries, and SQLite, with no table statistics, otherwise prefers the existing deleted_at index. A test checks SQLite's plan for each statement as GORM builds it. Rule suppressed: lll on the three event-tier model structs, whose struct tags cannot wrap. The resubmitted_from_id scan is left to #325. Model: opus-4-8 (implementation); opus-5-5 (rework)
47 lines
1.8 KiB
Go
47 lines
1.8 KiB
Go
package database
|
|
|
|
import (
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// Event represents a captured webhook event
|
|
//
|
|
//nolint:lll // a struct tag cannot wrap
|
|
type Event struct {
|
|
BaseModel
|
|
|
|
// CreatedAt and DeletedAt repeat the BaseModel fields only to index
|
|
// them for retention, which finds events by age. Its lookups carry
|
|
// GORM's "deleted_at IS NULL" (see DeliveryResult) and compare
|
|
// created_at with <, so their index has deleted_at first: SQLite
|
|
// narrows by a < only on the last column it uses. Its final delete
|
|
// has no deleted_at condition and uses the index on created_at
|
|
// alone. The other tables keep the unindexed BaseModel created_at.
|
|
CreatedAt time.Time `gorm:"index;index:idx_events_deleted_at_created_at,priority:2" json:"createdAt"`
|
|
DeletedAt gorm.DeletedAt `gorm:"index:idx_events_deleted_at_created_at,priority:1" json:"deletedAt,omitzero"`
|
|
|
|
WebhookID string `gorm:"type:uuid;not null" json:"webhookId"`
|
|
EntrypointID string `gorm:"type:uuid;not null" json:"entrypointId"`
|
|
|
|
// Request data
|
|
Method string `gorm:"not null" json:"method"`
|
|
Headers string `gorm:"type:text" json:"headers"` // JSON
|
|
Body string `gorm:"type:text" json:"body"`
|
|
ContentType string `json:"contentType"`
|
|
|
|
// ResubmittedFromID names the event this one was copied from by
|
|
// an operator resubmit. It is nil for an event that arrived on
|
|
// the receiver, which is every event created before the column
|
|
// existed. It is not a foreign key: the source event can be
|
|
// reaped by retention while its copies remain, and the id is
|
|
// kept as the record of where the copy came from either way.
|
|
ResubmittedFromID *string `gorm:"type:uuid;index" json:"resubmittedFromId,omitempty"`
|
|
|
|
// Relations
|
|
Webhook Webhook `json:"webhook,omitzero"`
|
|
Entrypoint Entrypoint `json:"entrypoint,omitzero"`
|
|
Deliveries []Delivery `json:"deliveries,omitempty"`
|
|
}
|