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