Documentation
¶
Overview ¶
Package store owns the database schema, GORM models, repositories, and the goose-driven migration runner. Callers depend on small interfaces declared where they consume the store (handler packages); only this package needs to know about GORM.
Index ¶
- Variables
- func MigrateDown(ctx context.Context, db *gorm.DB) error
- func MigrateStatus(ctx context.Context, db *gorm.DB) (string, error)
- func MigrateUp(ctx context.Context, db *gorm.DB) error
- func NewTestDB(t *testing.T) *gorm.DB
- func Open(url string) (*gorm.DB, error)
- func RawCreateForTest(db *gorm.DB, m SlackMessage) error
- func SQLDB(db *gorm.DB) (*sql.DB, error)
- type RepoMapping
- type SlackMessage
- type SlackMessages
- func (r *SlackMessages) Delete(ctx context.Context, repository string, prNumber int) error
- func (r *SlackMessages) DeleteStaleBefore(ctx context.Context, cutoff time.Time) (int64, error)
- func (r *SlackMessages) FindStuck(ctx context.Context, cutoff time.Time) ([]SlackMessage, error)
- func (r *SlackMessages) Get(ctx context.Context, repository string, prNumber int) (SlackMessage, error)
- func (r *SlackMessages) ListOpen(ctx context.Context) ([]SlackMessage, error)
- func (r *SlackMessages) MarkClosed(ctx context.Context, repository string, prNumber int) error
- func (r *SlackMessages) Save(ctx context.Context, m SlackMessage) error
- func (r *SlackMessages) Touch(ctx context.Context, repository string, prNumber int) error
Constants ¶
This section is empty.
Variables ¶
var ErrNotFound = errors.New("store: not found")
ErrNotFound is returned when a lookup matches no row.
Functions ¶
func MigrateDown ¶
MigrateDown rolls back the most recent migration.
func MigrateStatus ¶
MigrateStatus returns a human-readable list of each migration and whether it has been applied.
func NewTestDB ¶
NewTestDB returns a *gorm.DB backed by a fresh on-disk SQLite database inside t.TempDir, with all migrations applied. The database is closed and removed automatically when the test completes.
We use an on-disk file rather than `:memory:` because the goose-sqlite driver expects a stable database name to record migration state, and multiple in-memory connections in the same process are not always shared.
func Open ¶
Open opens a SQLite database for production use. The url accepts either a raw file path or the "file:..." DSN form used in our config defaults.
GORM's logger is silenced for "record not found" because we treat ErrNotFound as a normal return value, not a warning condition.
func RawCreateForTest ¶
func RawCreateForTest(db *gorm.DB, m SlackMessage) error
RawCreateForTest inserts a SlackMessage row preserving the caller's UpdatedAt and ClosedAt values, bypassing GORM's autoUpdateTime. Used by tests that need to seed rows with a controlled age and open/closed state.
Types ¶
type RepoMapping ¶
RepoMapping is the value object handlers and validators consume — a GitHub repository routed to a Slack channel with an optional mentions list. The source of truth lives in config.yaml's mappings: section (loaded by internal/config / internal/mappings); the type stays here so consumers don't have to know who produced it.
type SlackMessage ¶
type SlackMessage struct {
PRNumber int `gorm:"column:pr_number;primaryKey"`
Repository string `gorm:"column:gh_repository;primaryKey"`
TS string `gorm:"column:ts;not null"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;not null"`
ClosedAt *time.Time `gorm:"column:closed_at"`
}
SlackMessage tracks the Slack message thread-timestamp for one PR in one repository. (PRNumber, Repository) is the composite primary key — replaying the same PR event simply updates the TS.
UpdatedAt is bumped on Save (autoUpdateTime) and on Touch (review/comment activity); it drives both the scheduled cleanup of stale rows and the stuck-PR digest's idle detection. ClosedAt is set when the PR is merged/closed so the digest skips it; nil means the PR is still open.
func (SlackMessage) TableName ¶
func (SlackMessage) TableName() string
TableName pins the table name to match the migration; do not rely on GORM's pluralisation heuristics.
type SlackMessages ¶
type SlackMessages struct {
// contains filtered or unexported fields
}
SlackMessages persists the Slack message TS associated with each PR.
func NewSlackMessages ¶
func NewSlackMessages(db *gorm.DB) *SlackMessages
NewSlackMessages constructs a SlackMessages repository bound to db.
func (*SlackMessages) DeleteStaleBefore ¶
DeleteStaleBefore removes every row whose updated_at is strictly older than cutoff. Returns the number of rows deleted. An empty table returns (0, nil).
func (*SlackMessages) FindStuck ¶ added in v0.16.0
func (r *SlackMessages) FindStuck(ctx context.Context, cutoff time.Time) ([]SlackMessage, error)
FindStuck returns every open (closed_at IS NULL) message whose updated_at is strictly older than cutoff — the PRs that saw no activity since cutoff. Results are ordered oldest-first for stable digest output. An empty result is (nil, nil).
func (*SlackMessages) Get ¶
func (r *SlackMessages) Get(ctx context.Context, repository string, prNumber int) (SlackMessage, error)
Get returns the message for the given (repository, prNumber), or ErrNotFound.
func (*SlackMessages) ListOpen ¶ added in v0.16.0
func (r *SlackMessages) ListOpen(ctx context.Context) ([]SlackMessage, error)
ListOpen returns every message not yet marked closed, ordered for stable output. Used by the one-time reconcile to check each row against its real PR state on GitHub. An empty result is (nil, nil).
func (*SlackMessages) MarkClosed ¶ added in v0.16.0
MarkClosed records that the PR has been merged/closed so the stuck-PR digest skips it. A missing row is a no-op (idempotent).
func (*SlackMessages) Save ¶
func (r *SlackMessages) Save(ctx context.Context, m SlackMessage) error
Save upserts the message by composite key (pr_number, gh_repository). The `updated_at` column is bumped on every Save (both insert and update paths) to drive stale-row cleanup.