repositories

package
v0.0.0-...-8d3d8c4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 1, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrConflict = errors.New("record already exists")

ErrConflict is returned when an insert or update violates a unique constraint, for example when registering a user with an email that already exists.

View Source
var ErrNotFound = errors.New("record not found")

ErrNotFound is returned by repository methods when the requested record does not exist in the database. Callers should check for this error explicitly using errors.Is to distinguish missing records from other database errors.

user, err := repo.GetByID(ctx, id)
if errors.Is(err, repositories.ErrNotFound) {
    handle not found
}

Functions

This section is empty.

Types

type AgentFilter

type AgentFilter struct {
	Search string // case-insensitive substring match on name
	Status string // exact match on status (e.g. "online", "offline")
}

AgentFilter restricts results returned by AgentRepository.ListFiltered. Zero values mean "no filter" for that field.

type AgentRepository

type AgentRepository interface {
	Create(ctx context.Context, agent *db.Agent) error
	GetByID(ctx context.Context, id uuid.UUID) (*db.Agent, error)
	GetByHostname(ctx context.Context, hostname string) (*db.Agent, error)
	Update(ctx context.Context, agent *db.Agent) error
	UpdateStatus(ctx context.Context, id uuid.UUID, status string, lastSeenAt time.Time) error
	Delete(ctx context.Context, id uuid.UUID) error
	List(ctx context.Context, opts ListOptions) ([]db.Agent, int64, error)
	ListFiltered(ctx context.Context, filter AgentFilter, opts ListOptions) ([]db.Agent, int64, error)

	// TotalCount returns the count of all non-deleted agents in the database.
	// Used by telemetry to report the registered agent count regardless of
	// whether agents are currently connected.
	TotalCount(ctx context.Context) int
}

func NewAgentRepository

func NewAgentRepository(db *gorm.DB) AgentRepository

NewAgentRepository returns an AgentRepository backed by the provided *gorm.DB.

type AuditFilter

type AuditFilter struct {
	UserID       *uuid.UUID
	Action       string // prefix match: "policy." matches all policy events
	ResourceType string
	From         *time.Time
	To           *time.Time
}

AuditFilter restricts the result set returned by AuditRepository.List. Zero values mean "no filter" for that field.

type AuditRepository

type AuditRepository interface {
	Create(ctx context.Context, entry *db.AuditLog) error
	List(ctx context.Context, filter AuditFilter, opts ListOptions) ([]db.AuditLog, int64, error)
}

AuditRepository provides append-only access to the audit_log table. Records are never updated or deleted — only created and listed.

func NewAuditRepository

func NewAuditRepository(db *gorm.DB) AuditRepository

NewAuditRepository returns an AuditRepository backed by the provided *gorm.DB.

type DashboardRepository

type DashboardRepository interface {
	GetStats(ctx context.Context) (*DashboardStats, error)
}

DashboardRepository computes aggregated statistics for the dashboard. All queries are read-only and do not modify any data.

func NewDashboardRepository

func NewDashboardRepository(db *gorm.DB) DashboardRepository

NewDashboardRepository returns a DashboardRepository backed by the provided *gorm.DB.

type DashboardStats

type DashboardStats struct {
	// Agent counts
	AgentsTotal  int64
	AgentsOnline int64

	// Policy counts
	PoliciesTotal  int64
	PoliciesActive int64

	// Job counts for today (UTC)
	JobsTodayTotal     int64
	JobsTodaySucceeded int64
	JobsTodayFailed    int64

	// Snapshot totals (all time)
	SnapshotsTotal     int64
	SnapshotsTotalSize int64 // sum of size_bytes

	// Activity over the last 7 days (index 0 = oldest, index 6 = today)
	JobActivity  []DayJobActivity
	SizeActivity []DaySizeActivity
}

DashboardStats holds all aggregated data needed by the dashboard endpoint. It is computed in a single repository call that executes several lightweight SQL queries in sequence — fast because all are index-backed COUNT/SUM queries.

type DayJobActivity

type DayJobActivity struct {
	Date      string // "YYYY-MM-DD"
	Succeeded int64
	Failed    int64
}

DayJobActivity holds the succeeded and failed job counts for a single calendar day.

type DaySizeActivity

type DaySizeActivity struct {
	Date      string // "YYYY-MM-DD"
	SizeBytes int64
}

DaySizeActivity holds the total bytes backed up for a single calendar day, derived from snapshot records created on that day.

type DestinationFilter

type DestinationFilter struct {
	Search string // case-insensitive substring match on name
}

DestinationFilter restricts results returned by DestinationRepository.ListFiltered. Zero values mean "no filter" for that field.

type DestinationRepository

type DestinationRepository interface {
	Create(ctx context.Context, destination *db.Destination) error
	GetByID(ctx context.Context, id uuid.UUID) (*db.Destination, error)
	Update(ctx context.Context, destination *db.Destination) error
	// UpdateRepoSize refreshes only the cached restic repository size and its
	// timestamp, leaving all other destination fields untouched.
	UpdateRepoSize(ctx context.Context, id uuid.UUID, sizeBytes int64, at time.Time) error
	Delete(ctx context.Context, id uuid.UUID) error
	List(ctx context.Context, opts ListOptions) ([]db.Destination, int64, error)
	ListFiltered(ctx context.Context, filter DestinationFilter, opts ListOptions) ([]db.Destination, int64, error)
}

func NewDestinationRepository

func NewDestinationRepository(db *gorm.DB) DestinationRepository

NewDestinationRepository returns a DestinationRepository backed by the provided *gorm.DB.

type JobDestinationWithName

type JobDestinationWithName struct {
	db.JobDestination
	DestinationName string
}

JobDestinationWithName extends db.JobDestination with the destination's display name, resolved via LEFT JOIN in ListDestinationsByJob. LEFT JOIN ensures rows survive even if the destination was deleted.

type JobFilter

type JobFilter struct {
	Status string // e.g. "pending", "running", "succeeded", "failed", "cancelled"
	Type   string // e.g. "backup", "restore"
}

JobFilter restricts the result set returned by JobRepository.ListFiltered. Zero values mean "no filter" for that field.

type JobRepository

type JobRepository interface {
	Create(ctx context.Context, job *db.Job) error
	GetByID(ctx context.Context, id uuid.UUID) (*db.Job, error)
	GetByIDWithDetails(ctx context.Context, id uuid.UUID) (*JobWithNames, []JobDestinationWithName, []db.JobLog, error)
	Update(ctx context.Context, job *db.Job) error
	UpdateStatus(ctx context.Context, id uuid.UUID, status string, startedAt *time.Time, endedAt *time.Time, errMsg string) error
	FailRunningJobsForAgent(ctx context.Context, agentID uuid.UUID, errMsg string) (int64, error)
	List(ctx context.Context, opts ListOptions) ([]JobWithNames, int64, error)
	ListFiltered(ctx context.Context, filter JobFilter, opts ListOptions) ([]JobWithNames, int64, error)
	ListByType(ctx context.Context, jobType string, opts ListOptions) ([]JobWithNames, int64, error)
	ListByPolicy(ctx context.Context, policyID uuid.UUID, opts ListOptions) ([]JobWithNames, int64, error)
	ListByAgent(ctx context.Context, agentID uuid.UUID, opts ListOptions) ([]JobWithNames, int64, error)
	HasPendingJob(ctx context.Context, policyID uuid.UUID) (bool, error)

	// JobDestination
	CreateDestination(ctx context.Context, jd *db.JobDestination) error
	ListDestinationsByJob(ctx context.Context, jobID uuid.UUID) ([]JobDestinationWithName, error)
	UpdateDestinationStatus(ctx context.Context, jobID uuid.UUID, destID uuid.UUID, status string, startedAt *time.Time, endedAt *time.Time, snapshotID string, sizeBytes int64, errMsg string) error

	// JobLog
	BulkCreateLogs(ctx context.Context, logs []db.JobLog) error
	GetLogs(ctx context.Context, jobID uuid.UUID) ([]db.JobLog, error)
}

func NewJobRepository

func NewJobRepository(db *gorm.DB) JobRepository

NewJobRepository returns a JobRepository backed by the provided *gorm.DB.

type JobWithNames

type JobWithNames struct {
	db.Job
	PolicyName string
	AgentName  string
}

JobWithNames extends db.Job with denormalised policy and agent names. Populated via LEFT JOIN in the List* methods so the API can return display-ready responses without per-row lookups. LEFT JOIN ensures jobs whose policy or agent has been soft-deleted still appear (names = "").

type ListOptions

type ListOptions struct {
	Limit    int
	Offset   int
	SortBy   string
	SortDesc bool
}

ListOptions contains common pagination and filtering options for list queries. SortBy/SortDesc are optional; repositories that support sorting map SortBy to a whitelisted column (unknown/empty values fall back to the default order). Repositories that don't support sorting simply ignore these fields.

type NotificationRepository

type NotificationRepository interface {
	Create(ctx context.Context, notification *db.Notification) error
	GetByID(ctx context.Context, id uuid.UUID) (*db.Notification, error)
	MarkAsRead(ctx context.Context, id uuid.UUID) error
	MarkAllAsRead(ctx context.Context, userID uuid.UUID) error
	Delete(ctx context.Context, id uuid.UUID) error
	ListByUser(ctx context.Context, userID uuid.UUID, opts ListOptions) ([]db.Notification, int64, error)
	DeleteReadOlderThan(ctx context.Context, t time.Time) error

	// CreateDelivery inserts a new delivery row for the given channel type.
	CreateDelivery(ctx context.Context, d *db.NotificationDelivery) error

	// UpdateDelivery persists a delivery row after a send attempt (status,
	// attempts, last_error, next_retry_at are the fields typically changed).
	UpdateDelivery(ctx context.Context, d *db.NotificationDelivery) error

	// ListPendingDeliveries returns up to limit delivery rows whose status is
	// "pending" and whose next_retry_at is at or before `before`.
	// Used by the retrier to find work to process.
	ListPendingDeliveries(ctx context.Context, before time.Time, limit int) ([]*db.NotificationDelivery, error)

	// ListDeliveriesByStatus returns delivery rows filtered by status, ordered
	// newest first. Used by the admin queue visibility endpoint.
	ListDeliveriesByStatus(ctx context.Context, status string, opts ListOptions) ([]db.NotificationDelivery, int64, error)
}

func NewNotificationRepository

func NewNotificationRepository(db *gorm.DB) NotificationRepository

NewNotificationRepository returns a NotificationRepository backed by the provided *gorm.DB.

type OIDCProviderRepository

type OIDCProviderRepository interface {
	Create(ctx context.Context, provider *db.OIDCProvider) error
	GetByID(ctx context.Context, id uuid.UUID) (*db.OIDCProvider, error)
	List(ctx context.Context) ([]*db.OIDCProvider, error)
	ListEnabled(ctx context.Context) ([]*db.OIDCProvider, error)
	Update(ctx context.Context, provider *db.OIDCProvider) error
	Delete(ctx context.Context, id uuid.UUID) error
}

func NewOIDCProviderRepository

func NewOIDCProviderRepository(db *gorm.DB) OIDCProviderRepository

NewOIDCProviderRepository returns an OIDCProviderRepository backed by the provided *gorm.DB.

type PasswordResetTokenRepository

type PasswordResetTokenRepository interface {
	Create(ctx context.Context, token *db.PasswordResetToken) error
	// GetUnusedByHash returns an unused token matching the hash. Expiry is
	// checked by the caller in Go (timezone-safe), mirroring refresh tokens.
	// Returns ErrNotFound if no unused token matches.
	GetUnusedByHash(ctx context.Context, hash string) (*db.PasswordResetToken, error)
	MarkUsed(ctx context.Context, id uuid.UUID) error
	// DeleteByUserID removes all reset tokens for a user, invalidating any
	// outstanding links when a new reset is requested.
	DeleteByUserID(ctx context.Context, userID uuid.UUID) error
}

func NewPasswordResetTokenRepository

func NewPasswordResetTokenRepository(db *gorm.DB) PasswordResetTokenRepository

NewPasswordResetTokenRepository returns a PasswordResetTokenRepository backed by the provided *gorm.DB.

type PolicyDestinationWithName

type PolicyDestinationWithName struct {
	db.PolicyDestination
	DestinationName string
}

PolicyDestinationWithName extends db.PolicyDestination with the denormalised destination name resolved via JOIN. Deleted destinations are excluded from all queries that return this type.

type PolicyRepository

type PolicyRepository interface {
	Create(ctx context.Context, policy *db.Policy) error
	GetByID(ctx context.Context, id uuid.UUID) (*db.Policy, error)

	// GetByIDWithDestinations retrieves a policy together with its associated
	// PolicyDestination records. The destinations are returned as a separate
	// slice rather than embedded in the Policy struct, because GORM cannot
	// auto-resolve UUID-typed foreign keys. Callers iterate the slice directly.
	// Destinations that have been deleted are excluded automatically.
	GetByIDWithDestinations(ctx context.Context, id uuid.UUID) (*db.Policy, []PolicyDestinationWithName, error)

	Update(ctx context.Context, policy *db.Policy) error
	Delete(ctx context.Context, id uuid.UUID) error
	List(ctx context.Context, opts ListOptions) ([]db.Policy, int64, error)
	ListByAgent(ctx context.Context, agentID uuid.UUID) ([]db.Policy, error)
	ListEnabled(ctx context.Context) ([]db.Policy, error)
	UpdateSchedule(ctx context.Context, id uuid.UUID, lastRunAt, nextRunAt time.Time) error

	// ActivePoliciesCount returns the count of enabled, non-deleted policies.
	// Used by telemetry.
	ActivePoliciesCount(ctx context.Context) int

	// PolicyDestination
	AddDestination(ctx context.Context, pd *db.PolicyDestination) error
	RemoveDestination(ctx context.Context, policyID, destinationID uuid.UUID) error
	UpdateDestinationPriority(ctx context.Context, policyID, destinationID uuid.UUID, priority int) error
	DeleteAllDestinations(ctx context.Context, policyID uuid.UUID) error
	DeleteDestinationAssociations(ctx context.Context, destinationID uuid.UUID) error
	// GetDestinations returns active (non-deleted) destination associations for a
	// policy ordered by priority. Deleted destinations are excluded automatically.
	GetDestinations(ctx context.Context, policyID uuid.UUID) ([]PolicyDestinationWithName, error)
}

func NewPolicyRepository

func NewPolicyRepository(db *gorm.DB) PolicyRepository

NewPolicyRepository returns a PolicyRepository backed by the provided *gorm.DB.

type RefreshTokenRepository

type RefreshTokenRepository interface {
	Create(ctx context.Context, token *db.RefreshToken) error
	GetByHash(ctx context.Context, hash string) (*db.RefreshToken, error)
	DeleteByHash(ctx context.Context, hash string) error
	Revoke(ctx context.Context, id uuid.UUID) error
	RevokeAllForUser(ctx context.Context, userID uuid.UUID) error
	DeleteExpired(ctx context.Context) error
}

func NewRefreshTokenRepository

func NewRefreshTokenRepository(db *gorm.DB) RefreshTokenRepository

NewRefreshTokenRepository returns a RefreshTokenRepository backed by the provided *gorm.DB.

type SettingsRepository

type SettingsRepository interface {
	// Get retrieves a single setting by key. Returns ErrNotFound if absent.
	Get(ctx context.Context, key string) (*db.Setting, error)

	// Set creates or updates a setting (upsert semantics).
	Set(ctx context.Context, key string, value db.EncryptedString) error

	// GetMany retrieves multiple settings by key prefix (e.g. "smtp." returns
	// all SMTP settings). Returns an empty slice if none match.
	GetMany(ctx context.Context, prefix string) ([]db.Setting, error)

	// Delete removes a setting. No-op if the key does not exist.
	Delete(ctx context.Context, key string) error
}

SettingsRepository manages server configuration key-value pairs. It is the single point of access for the settings table — no other component should read or write settings directly.

func NewSettingsRepository

func NewSettingsRepository(database *gorm.DB) SettingsRepository

NewSettingsRepository creates a new SettingsRepository backed by GORM.

type SnapshotRepository

type SnapshotRepository interface {
	Create(ctx context.Context, snapshot *db.Snapshot) error
	GetByID(ctx context.Context, id uuid.UUID) (*db.Snapshot, error)
	Delete(ctx context.Context, id uuid.UUID) error
	DeleteBySnapshotID(ctx context.Context, snapshotID string) error
	ExistsBySnapshotIDAndDestination(ctx context.Context, snapshotID string, destinationID uuid.UUID) (bool, error)
	List(ctx context.Context, opts ListOptions) ([]SnapshotWithNames, int64, error)
	ListByPolicy(ctx context.Context, policyID uuid.UUID, opts ListOptions) ([]SnapshotWithNames, int64, error)
	ListByDestination(ctx context.Context, destinationID uuid.UUID, opts ListOptions) ([]SnapshotWithNames, int64, error)
}

func NewSnapshotRepository

func NewSnapshotRepository(db *gorm.DB) SnapshotRepository

NewSnapshotRepository returns a SnapshotRepository backed by the provided *gorm.DB.

type SnapshotWithNames

type SnapshotWithNames struct {
	db.Snapshot
	PolicyName      string
	DestinationName string
	AgentID         string
	AgentName       string
}

SnapshotWithNames extends db.Snapshot with denormalised display names resolved via JOIN. Used by list endpoints so the GUI does not need separate requests to resolve policy and destination names.

type UserRepository

type UserRepository interface {
	Create(ctx context.Context, user *db.User) error
	GetByID(ctx context.Context, id uuid.UUID) (*db.User, error)
	GetByEmail(ctx context.Context, email string) (*db.User, error)
	GetByOIDC(ctx context.Context, provider, sub string) (*db.User, error)
	Update(ctx context.Context, user *db.User) error
	Delete(ctx context.Context, id uuid.UUID) error
	List(ctx context.Context, opts ListOptions) ([]db.User, int64, error)
}

func NewUserRepository

func NewUserRepository(db *gorm.DB) UserRepository

NewUserRepository returns a UserRepository backed by the provided *gorm.DB.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL