Database: - Add slug, roaster_slug, brew_data_json columns to timeline_events - Migration backfills existing data from related tables - Remove 9-way LEFT JOIN from list query, read directly from columns Frontend: - Use CSS :nth-of-type(odd/even) for alternating timeline layout - Remove JavaScript class manipulation when appending month events - Simplify infinite scroll month-merging logic This eliminates query-time JOINs across 5 tables and ~20 lines of client-side JavaScript for pattern maintenance.
69 lines
2.3 KiB
SQL
69 lines
2.3 KiB
SQL
-- Add denormalized slug columns to timeline_events
|
|
-- This eliminates the need for 9-way JOINs when listing timeline events
|
|
|
|
-- Step 1: Add the new columns
|
|
ALTER TABLE timeline_events ADD COLUMN slug TEXT;
|
|
ALTER TABLE timeline_events ADD COLUMN roaster_slug TEXT;
|
|
ALTER TABLE timeline_events ADD COLUMN brew_data_json TEXT;
|
|
|
|
-- Step 2: Backfill roaster slugs for roaster events
|
|
UPDATE timeline_events
|
|
SET slug = (SELECT slug FROM roasters WHERE roasters.id = timeline_events.entity_id)
|
|
WHERE entity_type = 'roaster';
|
|
|
|
-- Step 3: Backfill slugs for roast events
|
|
UPDATE timeline_events
|
|
SET slug = (SELECT slug FROM roasts WHERE roasts.id = timeline_events.entity_id),
|
|
roaster_slug = (
|
|
SELECT ro.slug FROM roasts r
|
|
JOIN roasters ro ON r.roaster_id = ro.id
|
|
WHERE r.id = timeline_events.entity_id
|
|
)
|
|
WHERE entity_type = 'roast';
|
|
|
|
-- Step 4: Backfill slugs for bag events
|
|
UPDATE timeline_events
|
|
SET slug = (
|
|
SELECT r.slug FROM bags b
|
|
JOIN roasts r ON b.roast_id = r.id
|
|
WHERE b.id = timeline_events.entity_id
|
|
),
|
|
roaster_slug = (
|
|
SELECT ro.slug FROM bags b
|
|
JOIN roasts r ON b.roast_id = r.id
|
|
JOIN roasters ro ON r.roaster_id = ro.id
|
|
WHERE b.id = timeline_events.entity_id
|
|
)
|
|
WHERE entity_type = 'bag';
|
|
|
|
-- Step 5: Backfill slugs and brew_data for brew events
|
|
UPDATE timeline_events
|
|
SET slug = (
|
|
SELECT r.slug FROM brews br
|
|
JOIN bags b ON br.bag_id = b.id
|
|
JOIN roasts r ON b.roast_id = r.id
|
|
WHERE br.id = timeline_events.entity_id
|
|
),
|
|
roaster_slug = (
|
|
SELECT ro.slug FROM brews br
|
|
JOIN bags b ON br.bag_id = b.id
|
|
JOIN roasts r ON b.roast_id = r.id
|
|
JOIN roasters ro ON r.roaster_id = ro.id
|
|
WHERE br.id = timeline_events.entity_id
|
|
),
|
|
brew_data_json = (
|
|
SELECT json_object(
|
|
'bag_id', br.bag_id,
|
|
'grinder_id', br.grinder_id,
|
|
'brewer_id', br.brewer_id,
|
|
'coffee_weight', br.coffee_weight,
|
|
'grind_setting', br.grind_setting,
|
|
'water_volume', br.water_volume,
|
|
'water_temp', br.water_temp
|
|
)
|
|
FROM brews br
|
|
WHERE br.id = timeline_events.entity_id
|
|
)
|
|
WHERE entity_type = 'brew';
|
|
|
|
-- Gear events have no slug (entity_type = 'gear' gets NULL for both slug columns)
|