package history import ( "context" "database/sql" ) type BackfillCurrentFromObservationsResult struct { UpdatedComponentTypes int64 `json:"updated_component_types"` UpdatedInstallationSlots int64 `json:"updated_installation_slots"` } func (s *Service) BackfillCurrentFromObservations(ctx context.Context) (BackfillCurrentFromObservationsResult, error) { if s == nil || s.db == nil { return BackfillCurrentFromObservationsResult{}, sql.ErrConnDone } tx, err := s.db.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return BackfillCurrentFromObservationsResult{}, err } defer func() { _ = tx.Rollback() }() res1, err := tx.ExecContext(ctx, ` UPDATE parts p LEFT JOIN observations o ON o.id = ( SELECT o2.id FROM observations o2 WHERE o2.part_id = p.id AND JSON_EXTRACT(o2.details, '$.component_type') IS NOT NULL ORDER BY o2.observed_at DESC, o2.created_at DESC, o2.id DESC LIMIT 1 ) SET p.component_type = NULLIF(JSON_UNQUOTE(JSON_EXTRACT(o.details, '$.component_type')), '') WHERE (p.component_type IS NULL OR p.component_type = '')`) if err != nil { return BackfillCurrentFromObservationsResult{}, err } res2, err := tx.ExecContext(ctx, ` UPDATE installations i LEFT JOIN observations o ON o.id = ( SELECT o2.id FROM observations o2 WHERE o2.part_id = i.part_id ORDER BY o2.observed_at DESC, o2.created_at DESC, o2.id DESC LIMIT 1 ) SET i.slot_name = COALESCE( i.slot_name, NULLIF(JSON_UNQUOTE(JSON_EXTRACT(o.details, '$.slot')), ''), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(o.details, '$.attributes.location')), ''), CASE WHEN JSON_EXTRACT(o.details, '$.attributes.socket') IS NULL THEN NULL ELSE CONCAT('Socket ', JSON_UNQUOTE(JSON_EXTRACT(o.details, '$.attributes.socket'))) END, NULLIF(JSON_UNQUOTE(JSON_EXTRACT(o.details, '$.attributes.bdf')), '') ) WHERE i.removed_at IS NULL AND (i.slot_name IS NULL OR i.slot_name = '')`) if err != nil { return BackfillCurrentFromObservationsResult{}, err } if err := tx.Commit(); err != nil { return BackfillCurrentFromObservationsResult{}, err } updatedTypes, _ := res1.RowsAffected() updatedSlots, _ := res2.RowsAffected() return BackfillCurrentFromObservationsResult{UpdatedComponentTypes: updatedTypes, UpdatedInstallationSlots: updatedSlots}, nil }