package store import ( "context" "time" ) // NodeEngines are the engine builds chosen per node: node id, then engine, // then the build ("cu129") or "none". A node or engine not here is left to // the node's hardware. func (s *DB) NodeEngines(ctx context.Context) (map[string]map[string]string, error) { rows, err := s.db.QueryContext(ctx, `SELECT node_id, engine, variant FROM node_engines`) if err != nil { return nil, err } defer rows.Close() out := map[string]map[string]string{} for rows.Next() { var node, engine, variant string if err := rows.Scan(&node, &engine, &variant); err != nil { return nil, err } if out[node] == nil { out[node] = map[string]string{} } out[node][engine] = variant } return out, rows.Err() } // SetNodeEngine chooses an engine's build for a node; an empty variant // leaves it to the node's hardware again. func (s *DB) SetNodeEngine(ctx context.Context, node, engine, variant, by string) error { if variant == "" { _, err := s.db.ExecContext(ctx, `DELETE FROM node_engines WHERE node_id = ? AND engine = ?`, node, engine) return err } _, err := s.db.ExecContext(ctx, `INSERT INTO node_engines (node_id, engine, variant, updated_at, updated_by) VALUES (?, ?, ?, ?, ?) ON CONFLICT (node_id, engine) DO UPDATE SET variant = excluded.variant, updated_at = excluded.updated_at, updated_by = excluded.updated_by`, node, engine, variant, time.Now().UnixMilli(), by) return err }