package postgres import ( "context" "errors" "fmt" "git.cin.su/m/Assistant/contracts/capability" "github.com/jackc/pgx/v5/pgxpool" ) var ErrCapabilityHealthNotFound = errors.New("capability health not found") type CapabilityRepository struct{ pool *pgxpool.Pool } func OpenCapability(ctx context.Context, config ContinuityConfig) (*CapabilityRepository, error) { dsn := fmt.Sprintf("host=%s port=%s dbname=%s user=%s password=%s", config.Host, config.Port, config.Database, config.User, config.Password) pool, err := pgxpool.New(ctx, dsn) if err != nil { return nil, err } return &CapabilityRepository{pool: pool}, nil } func (r *CapabilityRepository) Close() { r.pool.Close() } func (r *CapabilityRepository) SaveHealth(ctx context.Context, health capability.Health) error { _, err := r.pool.Exec(ctx, `INSERT INTO capability.health (capability_id, state, reason, revision, semantic_version, observed_at_unix_millis) VALUES ($1,$2,$3,$4,$5,$6) ON CONFLICT (capability_id) DO UPDATE SET state=EXCLUDED.state, reason=EXCLUDED.reason, revision=EXCLUDED.revision, semantic_version=EXCLUDED.semantic_version, observed_at_unix_millis=EXCLUDED.observed_at_unix_millis WHERE capability.health.revision < EXCLUDED.revision`, health.CapabilityID, health.State, health.Reason, health.Revision, health.SemanticVersion, health.ObservedAtUnixMillis) return err } func (r *CapabilityRepository) LoadHealth(ctx context.Context, id capability.CapabilityID) (capability.Health, error) { var health capability.Health err := r.pool.QueryRow(ctx, `SELECT capability_id, state, reason, revision, semantic_version, observed_at_unix_millis FROM capability.health WHERE capability_id=$1`, id).Scan(&health.CapabilityID, &health.State, &health.Reason, &health.Revision, &health.SemanticVersion, &health.ObservedAtUnixMillis) if err != nil { return capability.Health{}, fmt.Errorf("load capability health: %w", err) } return health, nil } func (r *CapabilityRepository) RebuildHealthProjection(ctx context.Context) (int64, error) { tx, err := r.pool.Begin(ctx) if err != nil { return 0, err } defer tx.Rollback(ctx) if _, err = tx.Exec(ctx, `DELETE FROM capability.health_projection`); err != nil { return 0, err } result, err := tx.Exec(ctx, `INSERT INTO capability.health_projection (capability_id, state, reason, revision, semantic_version, observed_at_unix_millis) SELECT capability_id, state, reason, revision, semantic_version, observed_at_unix_millis FROM capability.health`) if err != nil { return 0, err } if err = tx.Commit(ctx); err != nil { return 0, err } return result.RowsAffected(), nil }