package db import ( "database/sql" "fmt" "lostcavewireplanner/internal/models" ) func (s *Store) ConnectionTypeGetAll() ([]models.ConnectionType, error) { rows, err := s.DB.Query(`SELECT id, name FROM connection_types ORDER BY id`) if err != nil { return nil, err } defer rows.Close() var types []models.ConnectionType for rows.Next() { var ct models.ConnectionType if err := rows.Scan(&ct.ID, &ct.Name); err != nil { return nil, err } types = append(types, ct) } return types, rows.Err() } func (s *Store) ConnectionGetByPortID(portID int64) (*models.Connection, error) { c := &models.Connection{} err := s.DB.QueryRow(`SELECT id, connection_type_id, label_1, label_2, color, port_id_1, port_id_2, created_at, updated_at FROM connections WHERE port_id_1 = ? OR port_id_2 = ?`, portID, portID). Scan(&c.ID, &c.ConnectionTypeID, &c.Label1, &c.Label2, &c.Color, &c.PortID1, &c.PortID2, &c.CreatedAt, &c.UpdatedAt) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, err } s.populateConnection(c) return c, nil } func (s *Store) ConnectionGetByPortIDExcluding(portID int64, excludeConnID int64) (*models.Connection, error) { c := &models.Connection{} err := s.DB.QueryRow(`SELECT id, connection_type_id, label_1, label_2, color, port_id_1, port_id_2, created_at, updated_at FROM connections WHERE (port_id_1 = ? OR port_id_2 = ?) AND id != ?`, portID, portID, excludeConnID). Scan(&c.ID, &c.ConnectionTypeID, &c.Label1, &c.Label2, &c.Color, &c.PortID1, &c.PortID2, &c.CreatedAt, &c.UpdatedAt) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, err } s.populateConnection(c) return c, nil } func (s *Store) ConnectionGetByID(id int64) (*models.Connection, error) { c := &models.Connection{} err := s.DB.QueryRow(`SELECT id, connection_type_id, label_1, label_2, color, port_id_1, port_id_2, created_at, updated_at FROM connections WHERE id = ?`, id). Scan(&c.ID, &c.ConnectionTypeID, &c.Label1, &c.Label2, &c.Color, &c.PortID1, &c.PortID2, &c.CreatedAt, &c.UpdatedAt) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, err } s.populateConnection(c) return c, nil } func (s *Store) ConnectionGetAllForRack(rackID int64) ([]models.Connection, error) { rows, err := s.DB.Query(` SELECT c.id, c.connection_type_id, c.label_1, c.label_2, c.color, c.port_id_1, c.port_id_2, c.created_at, c.updated_at FROM connections c WHERE (port_id_1 IN (SELECT dp.id FROM device_ports dp JOIN devices d ON d.id = dp.device_id WHERE d.rack_id = ?)) OR (port_id_2 IN (SELECT dp.id FROM device_ports dp JOIN devices d ON d.id = dp.device_id WHERE d.rack_id = ?))`, rackID, rackID) if err != nil { return nil, err } defer rows.Close() var conns []models.Connection for rows.Next() { var c models.Connection if err := rows.Scan(&c.ID, &c.ConnectionTypeID, &c.Label1, &c.Label2, &c.Color, &c.PortID1, &c.PortID2, &c.CreatedAt, &c.UpdatedAt); err != nil { return nil, err } s.populateConnection(&c) conns = append(conns, c) } return conns, rows.Err() } func (s *Store) ConnectionGetAll() ([]models.Connection, error) { rows, err := s.DB.Query(`SELECT id, connection_type_id, label_1, label_2, color, port_id_1, port_id_2, created_at, updated_at FROM connections`) if err != nil { return nil, err } defer rows.Close() var conns []models.Connection for rows.Next() { var c models.Connection if err := rows.Scan(&c.ID, &c.ConnectionTypeID, &c.Label1, &c.Label2, &c.Color, &c.PortID1, &c.PortID2, &c.CreatedAt, &c.UpdatedAt); err != nil { return nil, err } conns = append(conns, c) } return conns, rows.Err() } func (s *Store) ConnectionCreate(c *models.Connection) error { tx, err := s.DB.Begin() if err != nil { return err } defer tx.Rollback() if c.PortID1 != nil { exists, err := s.portConnectedTx(tx, *c.PortID1) if err != nil { return err } if exists { return fmt.Errorf("port %d is already connected", *c.PortID1) } } if c.PortID2 != nil { exists, err := s.portConnectedTx(tx, *c.PortID2) if err != nil { return err } if exists { return fmt.Errorf("port %d is already connected", *c.PortID2) } } res, err := tx.Exec(`INSERT INTO connections (connection_type_id, label_1, label_2, color, port_id_1, port_id_2) VALUES (?, ?, ?, ?, ?, ?)`, c.ConnectionTypeID, c.Label1, c.Label2, c.Color, c.PortID1, c.PortID2) if err != nil { return err } c.ID, err = res.LastInsertId() if err != nil { return err } return tx.Commit() } func (s *Store) ConnectionUpdate(c *models.Connection) error { _, err := s.DB.Exec(`UPDATE connections SET connection_type_id=?, label_1=?, label_2=?, color=?, port_id_1=?, port_id_2=?, updated_at=datetime('now') WHERE id=?`, c.ConnectionTypeID, c.Label1, c.Label2, c.Color, c.PortID1, c.PortID2, c.ID) return err } func (s *Store) ConnectionDelete(id int64) error { _, err := s.DB.Exec(`DELETE FROM connections WHERE id=?`, id) return err } func (s *Store) portConnectedTx(tx *sql.Tx, portID int64) (bool, error) { var count int err := tx.QueryRow(`SELECT COUNT(*) FROM connections WHERE port_id_1 = ? OR port_id_2 = ?`, portID, portID).Scan(&count) return count > 0, err } func (s *Store) populateConnection(c *models.Connection) { if c.PortID1 != nil { c.Port1, _ = s.PortGetByID(*c.PortID1) if c.Port1 != nil { c.Device1, _ = s.DeviceGetByID(c.Port1.DeviceID) } } if c.PortID2 != nil { c.Port2, _ = s.PortGetByID(*c.PortID2) if c.Port2 != nil { c.Device2, _ = s.DeviceGetByID(c.Port2.DeviceID) } } ct, _ := s.ConnectionTypeGetByID(c.ConnectionTypeID) c.ConnectionType = ct } func (s *Store) ConnectionTypeGetByID(id int64) (*models.ConnectionType, error) { ct := &models.ConnectionType{} err := s.DB.QueryRow(`SELECT id, name FROM connection_types WHERE id = ?`, id).Scan(&ct.ID, &ct.Name) if err == sql.ErrNoRows { return nil, nil } if err != nil { return nil, err } return ct, nil }