# frozen_string_literal: true # Previously, the Slot table was holding data about reservations. # This was a wrong assumption that leads to a bug. # An Availability should have many slots but a slot can be related to multiple Reservations, # so a slot must not hold data about a single reservation (like `offered`),these data # should be stored in SlotsReservation instead. class AddReservationFieldsToSlotsReservations < ActiveRecord::Migration[5.2] def up add_column :slots_reservations, :ex_start_at, :datetime add_column :slots_reservations, :ex_end_at, :datetime add_column :slots_reservations, :canceled_at, :datetime add_column :slots_reservations, :offered, :boolean, default: false execute <<-SQL UPDATE slots_reservations SET ex_start_at=slots.ex_start_at, ex_end_at=slots.ex_end_at, canceled_at=slots.canceled_at, offered=slots.offered FROM slots WHERE slots_reservations.slot_id = slots.id SQL remove_column :slots, :ex_start_at remove_column :slots, :ex_end_at remove_column :slots, :canceled_at remove_column :slots, :offered remove_column :slots, :destroying # we gonna keep only only one slot (remove duplicates) because data is now hold in slots_reservations # update slots_reservation.slot_id execute <<-SQL UPDATE slots_reservations SET slot_id=r.kept FROM ( SELECT count(*), start_at, end_at, availability_id, min(id) AS kept, array_agg(id) AS all_ids FROM slots GROUP BY start_at, end_at, availability_id HAVING count(*) > 1) as r WHERE slot_id = ANY(r.all_ids); SQL # remove useless slots execute <<-SQL WITH same_slots AS ( SELECT count(*), start_at, end_at, availability_id, min(id) AS kept, array_agg(id) AS all_ids FROM slots GROUP BY start_at, end_at, availability_id HAVING count(*) > 1 ) DELETE FROM slots WHERE id IN (SELECT unnest(all_ids) FROM same_slots) AND id NOT IN (SELECT kept FROM same_slots); SQL end def down execute <<-SQL DO $$ DECLARE sr_group RECORD; slot slots%ROWTYPE; new_slot_id slots.id%TYPE; curr_slot_reservation_id slots_reservations.id%TYPE; BEGIN FOR sr_group IN SELECT count(*), array_agg(id) AS all_ids, slot_id FROM slots_reservations GROUP BY slot_id HAVING count(*) > 1 LOOP SELECT * INTO slot FROM slots WHERE id = sr_group.slot_id; FOR curr_slot_reservation_id IN SELECT unnest(sr_group.all_ids[2:]) LOOP INSERT INTO slots (start_at, end_at, created_at, updated_at, availability_id) VALUES (slot.start_at, slot.end_at, now(), now(), slot.availability_id) RETURNING id INTO new_slot_id; UPDATE slots_reservations SET slot_id=new_slot_id WHERE id=curr_slot_reservation_id; END LOOP; END LOOP; END; $$ SQL add_column :slots, :ex_start_at, :datetime add_column :slots, :ex_end_at, :datetime add_column :slots, :canceled_at, :datetime add_column :slots, :offered, :boolean, default: false add_column :slots, :destroying, :boolean, default: false execute <<-SQL UPDATE slots SET ex_start_at=slots_reservations.ex_start_at, ex_end_at=slots_reservations.ex_end_at, canceled_at=slots_reservations.canceled_at, offered=slots_reservations.offered FROM slots_reservations WHERE slots_reservations.slot_id = slots.id SQL remove_column :slots_reservations, :ex_start_at remove_column :slots_reservations, :ex_end_at remove_column :slots_reservations, :canceled_at remove_column :slots_reservations, :offered end end