//nolint:dupl // Active Record pattern - similar structure to label.go is intentional package models import ( "context" "database/sql" "errors" "fmt" "git.eeqj.de/sneak/upaas/internal/database" ) // EnvVar represents an environment variable for an app. type EnvVar struct { db *database.Database ID int64 AppID string Key string Value string } // NewEnvVar creates a new EnvVar with a database reference. func NewEnvVar(db *database.Database) *EnvVar { return &EnvVar{db: db} } // Save inserts or updates the env var in the database. func (e *EnvVar) Save(ctx context.Context) error { if e.ID == 0 { return e.insert(ctx) } return e.update(ctx) } // Delete removes the env var from the database. func (e *EnvVar) Delete(ctx context.Context) error { _, err := e.db.Exec(ctx, "DELETE FROM app_env_vars WHERE id = ?", e.ID) return err } func (e *EnvVar) insert(ctx context.Context) error { query := "INSERT INTO app_env_vars (app_id, key, value) VALUES (?, ?, ?)" result, err := e.db.Exec(ctx, query, e.AppID, e.Key, e.Value) if err != nil { return err } id, err := result.LastInsertId() if err != nil { return err } e.ID = id return nil } func (e *EnvVar) update(ctx context.Context) error { query := "UPDATE app_env_vars SET key = ?, value = ? WHERE id = ?" _, err := e.db.Exec(ctx, query, e.Key, e.Value, e.ID) return err } // FindEnvVar finds an env var by ID. // //nolint:nilnil // returning nil,nil is idiomatic for "not found" in Active Record func FindEnvVar( ctx context.Context, db *database.Database, id int64, ) (*EnvVar, error) { envVar := NewEnvVar(db) row := db.QueryRow(ctx, "SELECT id, app_id, key, value FROM app_env_vars WHERE id = ?", id, ) err := row.Scan(&envVar.ID, &envVar.AppID, &envVar.Key, &envVar.Value) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, nil } return nil, fmt.Errorf("scanning env var: %w", err) } return envVar, nil } // FindEnvVarsByAppID finds all env vars for an app. func FindEnvVarsByAppID( ctx context.Context, db *database.Database, appID string, ) ([]*EnvVar, error) { query := ` SELECT id, app_id, key, value FROM app_env_vars WHERE app_id = ? ORDER BY key` rows, err := db.Query(ctx, query, appID) if err != nil { return nil, fmt.Errorf("querying env vars by app: %w", err) } defer func() { _ = rows.Close() }() var envVars []*EnvVar for rows.Next() { envVar := NewEnvVar(db) scanErr := rows.Scan( &envVar.ID, &envVar.AppID, &envVar.Key, &envVar.Value, ) if scanErr != nil { return nil, scanErr } envVars = append(envVars, envVar) } return envVars, rows.Err() } // DeleteEnvVarsByAppID deletes all env vars for an app. func DeleteEnvVarsByAppID( ctx context.Context, db *database.Database, appID string, ) error { _, err := db.Exec(ctx, "DELETE FROM app_env_vars WHERE app_id = ?", appID) return err }