|
| 1 | +DO $$ |
| 2 | +DECLARE |
| 3 | + chunk_size INTEGER := 1000; |
| 4 | + start_id INTEGER := 1; -- Starting ID |
| 5 | + end_id INTEGER; -- Will be set dynamically |
| 6 | + current_id INTEGER; |
| 7 | + |
| 8 | + processed_count INTEGER := 0; |
| 9 | + chunk_updated_count INTEGER := 0; |
| 10 | + total_count INTEGER; |
| 11 | +BEGIN |
| 12 | + -- Get the maximum ID and total count from the App_RoutingForms_FormResponse table |
| 13 | + SELECT COALESCE(MAX(id), 0) INTO end_id FROM "App_RoutingForms_FormResponse"; |
| 14 | + SELECT COUNT(*) INTO total_count FROM "App_RoutingForms_FormResponse"; |
| 15 | + |
| 16 | + -- Handle case where there are no records to process |
| 17 | + IF total_count = 0 THEN |
| 18 | + RAISE NOTICE 'No records found in App_RoutingForms_FormResponse table. Migration completed.'; |
| 19 | + RETURN; |
| 20 | + END IF; |
| 21 | + |
| 22 | + RAISE NOTICE 'Starting migration: processing up to ID % (total responses: %)', end_id, total_count; |
| 23 | + |
| 24 | + FOR current_id IN SELECT * FROM generate_series(start_id, end_id, chunk_size) |
| 25 | + LOOP |
| 26 | + -- Use UPSERT to only update records that are missing or have incorrect data |
| 27 | + WITH expected_data AS ( |
| 28 | + SELECT |
| 29 | + r.id, |
| 30 | + r."formId" as expected_form_id, |
| 31 | + f.name as expected_form_name, |
| 32 | + f."teamId" as expected_form_team_id, |
| 33 | + f."userId" as expected_form_user_id, |
| 34 | + b.uid as expected_booking_uid, |
| 35 | + b.id as expected_booking_id, |
| 36 | + b.status as expected_booking_status, |
| 37 | + calculate_booking_status_order(b.status::text) as expected_booking_status_order, |
| 38 | + b."createdAt" as expected_booking_created_at, |
| 39 | + b."startTime" as expected_booking_start_time, |
| 40 | + b."endTime" as expected_booking_end_time, |
| 41 | + b."userId" as expected_booking_user_id, |
| 42 | + u.name as expected_booking_user_name, |
| 43 | + u.email as expected_booking_user_email, |
| 44 | + u."avatarUrl" as expected_booking_user_avatar_url, |
| 45 | + COALESCE( |
| 46 | + ( |
| 47 | + SELECT ar."reasonString" |
| 48 | + FROM "AssignmentReason" ar |
| 49 | + WHERE ar."bookingId" = b.id |
| 50 | + LIMIT 1 |
| 51 | + ), |
| 52 | + '' |
| 53 | + ) as expected_booking_assignment_reason, |
| 54 | + et.id as expected_event_type_id, |
| 55 | + et."parentId" as expected_event_type_parent_id, |
| 56 | + et."schedulingType"::text as expected_event_type_scheduling_type, |
| 57 | + r."createdAt" as expected_created_at, |
| 58 | + t.utm_source as expected_utm_source, |
| 59 | + t.utm_medium as expected_utm_medium, |
| 60 | + t.utm_campaign as expected_utm_campaign, |
| 61 | + t.utm_term as expected_utm_term, |
| 62 | + t.utm_content as expected_utm_content |
| 63 | + FROM "App_RoutingForms_FormResponse" r |
| 64 | + INNER JOIN "App_RoutingForms_Form" f ON r."formId" = f.id |
| 65 | + LEFT JOIN "Booking" b ON b.uid = r."routedToBookingUid" |
| 66 | + LEFT JOIN "users" u ON b."userId" = u.id |
| 67 | + LEFT JOIN "EventType" et ON b."eventTypeId" = et.id |
| 68 | + LEFT JOIN "Tracking" t ON t."bookingId" = b.id |
| 69 | + WHERE r.id BETWEEN current_id AND current_id + chunk_size - 1 |
| 70 | + ), |
| 71 | + records_to_update AS ( |
| 72 | + SELECT e.* |
| 73 | + FROM expected_data e |
| 74 | + LEFT JOIN "RoutingFormResponseDenormalized" d ON e.id = d.id |
| 75 | + WHERE CASE |
| 76 | + WHEN d.id IS NULL THEN true -- Include missing records |
| 77 | + WHEN d."formId" IS DISTINCT FROM e.expected_form_id THEN true |
| 78 | + WHEN d."formName" IS DISTINCT FROM e.expected_form_name THEN true |
| 79 | + WHEN d."formTeamId" IS DISTINCT FROM e.expected_form_team_id THEN true |
| 80 | + WHEN d."formUserId" IS DISTINCT FROM e.expected_form_user_id THEN true |
| 81 | + WHEN d."bookingUid" IS DISTINCT FROM e.expected_booking_uid THEN true |
| 82 | + WHEN d."bookingId" IS DISTINCT FROM e.expected_booking_id THEN true |
| 83 | + WHEN d."bookingStatus" IS DISTINCT FROM e.expected_booking_status THEN true |
| 84 | + WHEN d."bookingStatusOrder" IS DISTINCT FROM e.expected_booking_status_order THEN true |
| 85 | + WHEN d."bookingCreatedAt" IS DISTINCT FROM e.expected_booking_created_at THEN true |
| 86 | + WHEN d."bookingStartTime" IS DISTINCT FROM e.expected_booking_start_time THEN true |
| 87 | + WHEN d."bookingEndTime" IS DISTINCT FROM e.expected_booking_end_time THEN true |
| 88 | + WHEN d."bookingUserId" IS DISTINCT FROM e.expected_booking_user_id THEN true |
| 89 | + WHEN d."bookingUserName" IS DISTINCT FROM e.expected_booking_user_name THEN true |
| 90 | + WHEN d."bookingUserEmail" IS DISTINCT FROM e.expected_booking_user_email THEN true |
| 91 | + WHEN d."bookingUserAvatarUrl" IS DISTINCT FROM e.expected_booking_user_avatar_url THEN true |
| 92 | + WHEN d."bookingAssignmentReason" IS DISTINCT FROM e.expected_booking_assignment_reason THEN true |
| 93 | + WHEN d."eventTypeId" IS DISTINCT FROM e.expected_event_type_id THEN true |
| 94 | + WHEN d."eventTypeParentId" IS DISTINCT FROM e.expected_event_type_parent_id THEN true |
| 95 | + WHEN d."eventTypeSchedulingType"::text IS DISTINCT FROM e.expected_event_type_scheduling_type THEN true |
| 96 | + WHEN d."createdAt" IS DISTINCT FROM e.expected_created_at THEN true |
| 97 | + WHEN d."utm_source" IS DISTINCT FROM e.expected_utm_source THEN true |
| 98 | + WHEN d."utm_medium" IS DISTINCT FROM e.expected_utm_medium THEN true |
| 99 | + WHEN d."utm_campaign" IS DISTINCT FROM e.expected_utm_campaign THEN true |
| 100 | + WHEN d."utm_term" IS DISTINCT FROM e.expected_utm_term THEN true |
| 101 | + WHEN d."utm_content" IS DISTINCT FROM e.expected_utm_content THEN true |
| 102 | + ELSE false -- Don't include valid records |
| 103 | + END |
| 104 | + ) |
| 105 | + INSERT INTO "RoutingFormResponseDenormalized" ( |
| 106 | + id, |
| 107 | + "formId", |
| 108 | + "formName", |
| 109 | + "formTeamId", |
| 110 | + "formUserId", |
| 111 | + "bookingUid", |
| 112 | + "bookingId", |
| 113 | + "bookingStatus", |
| 114 | + "bookingStatusOrder", |
| 115 | + "bookingCreatedAt", |
| 116 | + "bookingStartTime", |
| 117 | + "bookingEndTime", |
| 118 | + "bookingUserId", |
| 119 | + "bookingUserName", |
| 120 | + "bookingUserEmail", |
| 121 | + "bookingUserAvatarUrl", |
| 122 | + "bookingAssignmentReason", |
| 123 | + "eventTypeId", |
| 124 | + "eventTypeParentId", |
| 125 | + "eventTypeSchedulingType", |
| 126 | + "createdAt", |
| 127 | + "utm_source", |
| 128 | + "utm_medium", |
| 129 | + "utm_campaign", |
| 130 | + "utm_term", |
| 131 | + "utm_content" |
| 132 | + ) |
| 133 | + SELECT |
| 134 | + r.id, |
| 135 | + r.expected_form_id, |
| 136 | + r.expected_form_name, |
| 137 | + r.expected_form_team_id, |
| 138 | + r.expected_form_user_id, |
| 139 | + r.expected_booking_uid, |
| 140 | + r.expected_booking_id, |
| 141 | + r.expected_booking_status, |
| 142 | + r.expected_booking_status_order, |
| 143 | + r.expected_booking_created_at, |
| 144 | + r.expected_booking_start_time, |
| 145 | + r.expected_booking_end_time, |
| 146 | + r.expected_booking_user_id, |
| 147 | + r.expected_booking_user_name, |
| 148 | + r.expected_booking_user_email, |
| 149 | + r.expected_booking_user_avatar_url, |
| 150 | + r.expected_booking_assignment_reason, |
| 151 | + r.expected_event_type_id, |
| 152 | + r.expected_event_type_parent_id, |
| 153 | + r.expected_event_type_scheduling_type::text, |
| 154 | + r.expected_created_at, |
| 155 | + r.expected_utm_source, |
| 156 | + r.expected_utm_medium, |
| 157 | + r.expected_utm_campaign, |
| 158 | + r.expected_utm_term, |
| 159 | + r.expected_utm_content |
| 160 | + FROM records_to_update r |
| 161 | + ON CONFLICT (id) DO UPDATE SET |
| 162 | + "formId" = EXCLUDED."formId", |
| 163 | + "formName" = EXCLUDED."formName", |
| 164 | + "formTeamId" = EXCLUDED."formTeamId", |
| 165 | + "formUserId" = EXCLUDED."formUserId", |
| 166 | + "bookingUid" = EXCLUDED."bookingUid", |
| 167 | + "bookingId" = EXCLUDED."bookingId", |
| 168 | + "bookingStatus" = EXCLUDED."bookingStatus", |
| 169 | + "bookingStatusOrder" = EXCLUDED."bookingStatusOrder", |
| 170 | + "bookingCreatedAt" = EXCLUDED."bookingCreatedAt", |
| 171 | + "bookingStartTime" = EXCLUDED."bookingStartTime", |
| 172 | + "bookingEndTime" = EXCLUDED."bookingEndTime", |
| 173 | + "bookingUserId" = EXCLUDED."bookingUserId", |
| 174 | + "bookingUserName" = EXCLUDED."bookingUserName", |
| 175 | + "bookingUserEmail" = EXCLUDED."bookingUserEmail", |
| 176 | + "bookingUserAvatarUrl" = EXCLUDED."bookingUserAvatarUrl", |
| 177 | + "bookingAssignmentReason" = EXCLUDED."bookingAssignmentReason", |
| 178 | + "eventTypeId" = EXCLUDED."eventTypeId", |
| 179 | + "eventTypeParentId" = EXCLUDED."eventTypeParentId", |
| 180 | + "eventTypeSchedulingType" = EXCLUDED."eventTypeSchedulingType", |
| 181 | + "createdAt" = EXCLUDED."createdAt", |
| 182 | + "utm_source" = EXCLUDED."utm_source", |
| 183 | + "utm_medium" = EXCLUDED."utm_medium", |
| 184 | + "utm_campaign" = EXCLUDED."utm_campaign", |
| 185 | + "utm_term" = EXCLUDED."utm_term", |
| 186 | + "utm_content" = EXCLUDED."utm_content"; |
| 187 | + |
| 188 | + GET DIAGNOSTICS chunk_updated_count = ROW_COUNT; |
| 189 | + processed_count := processed_count + chunk_updated_count; |
| 190 | + |
| 191 | + RAISE NOTICE 'Chunk processed: IDs %-% (updated/inserted: % records, total updated: %)', |
| 192 | + current_id, current_id + chunk_size - 1, chunk_updated_count, processed_count; |
| 193 | + END LOOP; |
| 194 | + |
| 195 | + RAISE NOTICE 'Migration completed: processed up to ID % (total updated/inserted: % records out of % total records)', |
| 196 | + end_id, processed_count, total_count; |
| 197 | +END $$; |
0 commit comments