package registry import ( "database/sql" "fmt" "time" ) // Service represents a service in the registry. type Service struct { Name string Active bool Comment string CreatedAt time.Time UpdatedAt time.Time } // CreateService creates a new service in the registry. func CreateService(db *sql.DB, name string, active bool, comment string) error { _, err := db.Exec( "INSERT INTO services (name, active, comment) VALUES (?, ?, ?)", name, active, comment, ) if err != nil { return fmt.Errorf("create service %q: %w", name, err) } return nil } // GetService retrieves a service by name. func GetService(db *sql.DB, name string) (*Service, error) { s := &Service{} var createdAt, updatedAt string err := db.QueryRow( "SELECT name, active, comment, created_at, updated_at FROM services WHERE name = ?", name, ).Scan(&s.Name, &s.Active, &s.Comment, &createdAt, &updatedAt) if err != nil { return nil, fmt.Errorf("get service %q: %w", name, err) } s.CreatedAt, _ = time.Parse("2006-01-02 15:04:05", createdAt) s.UpdatedAt, _ = time.Parse("2006-01-02 15:04:05", updatedAt) return s, nil } // ListServices returns all services. func ListServices(db *sql.DB) ([]Service, error) { rows, err := db.Query("SELECT name, active, comment, created_at, updated_at FROM services ORDER BY name") if err != nil { return nil, fmt.Errorf("list services: %w", err) } defer func() { _ = rows.Close() }() var services []Service for rows.Next() { var s Service var createdAt, updatedAt string if err := rows.Scan(&s.Name, &s.Active, &s.Comment, &createdAt, &updatedAt); err != nil { return nil, fmt.Errorf("scan service: %w", err) } s.CreatedAt, _ = time.Parse("2006-01-02 15:04:05", createdAt) s.UpdatedAt, _ = time.Parse("2006-01-02 15:04:05", updatedAt) services = append(services, s) } return services, rows.Err() } // UpdateServiceActive updates a service's active flag and comment. If comment // is empty, the existing comment is preserved. func UpdateServiceActive(db *sql.DB, name string, active bool, comment string) error { res, err := db.Exec(` UPDATE services SET active = ?, comment = CASE WHEN ? = '' THEN comment ELSE ? END, updated_at = datetime('now') WHERE name = ?`, active, comment, comment, name, ) if err != nil { return fmt.Errorf("update service %q: %w", name, err) } n, _ := res.RowsAffected() if n == 0 { return fmt.Errorf("update service %q: %w", name, sql.ErrNoRows) } return nil } // DeleteService removes a service and all its components (via CASCADE). func DeleteService(db *sql.DB, name string) error { res, err := db.Exec("DELETE FROM services WHERE name = ?", name) if err != nil { return fmt.Errorf("delete service %q: %w", name, err) } n, _ := res.RowsAffected() if n == 0 { return fmt.Errorf("delete service %q: %w", name, sql.ErrNoRows) } return nil }