check / check (push) Waiting to run
The event log's resubmit count, run on every page load over up to 25 event ids, read every live event in the webhook's database: GORM adds deleted_at IS NULL, and SQLite, keeping no statistics there, chose the deleted_at index over the resubmitted_from_id one. deleted_at is now the second column of idx_events_resubmitted_from_id, so the count is answered from that index for a whole page of events. A test checks SQLite's plan for the statement as GORM builds it, with a full page of ids. The README's event-tier indexes table lists the index. Pre-1.0: the index changes in the schema in place, with nothing for older databases. Model: opus-5-5
55 lines
2.3 KiB
Go
55 lines
2.3 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.
|
|
// DeletedAt is also the second column of the resubmitted_from_id
|
|
// index, for the reason DeliveryResult gives.
|
|
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;index:idx_events_resubmitted_from_id,priority:2" 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"`
|
|
|
|
// BodyBytes is the size of Body in bytes, recorded when the event
|
|
// is stored so the recent events list can show it without reading
|
|
// the body.
|
|
BodyBytes int64 `gorm:"not null" json:"bodyBytes"`
|
|
|
|
// 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:idx_events_resubmitted_from_id,priority:1" json:"resubmittedFromId,omitempty"`
|
|
|
|
// Relations. No model marshals the record it belongs to, so
|
|
// Webhook and Entrypoint are left out of the JSON.
|
|
Webhook Webhook `json:"-"`
|
|
Entrypoint Entrypoint `json:"-"`
|
|
Deliveries []Delivery `json:"deliveries,omitempty"`
|
|
}
|