package registry import ( "context" "database/sql" "reanimator/internal/domain" ) type ComponentRepository struct { db *sql.DB } func NewComponentRepository(db *sql.DB) *ComponentRepository { return &ComponentRepository{db: db} } func (r *ComponentRepository) Create(ctx context.Context, component domain.Component) (domain.Component, error) { var lotID interface{} if component.LotID != nil { lotID = *component.LotID } var firstSeen interface{} if component.FirstSeenAt != nil { firstSeen = *component.FirstSeenAt } result, err := r.db.ExecContext(ctx, `INSERT INTO components (lot_id, vendor, model, vendor_serial, first_seen_at) VALUES (?, ?, ?, ?, ?)`, lotID, component.Vendor, component.Model, component.VendorSerial, firstSeen, ) if err != nil { return domain.Component{}, classifyError(err) } id, err := result.LastInsertId() if err != nil { return domain.Component{}, err } return r.Get(ctx, id) } func (r *ComponentRepository) Get(ctx context.Context, id int64) (domain.Component, error) { var component domain.Component var lotID sql.NullInt64 var vendor sql.NullString var model sql.NullString var firstSeen sql.NullTime row := r.db.QueryRowContext(ctx, `SELECT id, lot_id, vendor, model, vendor_serial, first_seen_at, created_at, updated_at FROM components WHERE id = ?`, id, ) if err := row.Scan(&component.ID, &lotID, &vendor, &model, &component.VendorSerial, &firstSeen, &component.CreatedAt, &component.UpdatedAt); err != nil { if err == sql.ErrNoRows { return domain.Component{}, ErrNotFound } return domain.Component{}, err } component.LotID = nullInt64ToPtr(lotID) component.Vendor = nullStringToPtr(vendor) component.Model = nullStringToPtr(model) component.FirstSeenAt = nullTimeToPtr(firstSeen) return component, nil } func (r *ComponentRepository) List(ctx context.Context) ([]domain.Component, error) { rows, err := r.db.QueryContext(ctx, `SELECT id, lot_id, vendor, model, vendor_serial, first_seen_at, created_at, updated_at FROM components ORDER BY id`, ) if err != nil { return nil, err } defer rows.Close() components := make([]domain.Component, 0) for rows.Next() { var component domain.Component var lotID sql.NullInt64 var vendor sql.NullString var model sql.NullString var firstSeen sql.NullTime if err := rows.Scan(&component.ID, &lotID, &vendor, &model, &component.VendorSerial, &firstSeen, &component.CreatedAt, &component.UpdatedAt); err != nil { return nil, err } component.LotID = nullInt64ToPtr(lotID) component.Vendor = nullStringToPtr(vendor) component.Model = nullStringToPtr(model) component.FirstSeenAt = nullTimeToPtr(firstSeen) components = append(components, component) } if err := rows.Err(); err != nil { return nil, err } return components, nil }