Powered by AppSignal & Oban Pro

Day 4

2025/day4/day4.livemd

Day 4

Mix.install([
  {:ecto_sql, "~> 3.10"},
  {:postgrex, ">= 0.0.0"},
  {:kino, "~> 0.18.0"}
])

Application.put_env(:myapp, Repo,
  url: "ecto://postgres:postgres@localhost/advent_of_sql_2025"
)

defmodule Repo do
  use Ecto.Repo, adapter: Ecto.Adapters.Postgres, otp_app: :myapp
end

{:ok, _pid} = Repo.start_link()

Setup

import Ecto.Query

defmodule OfficialShifts do
  use Ecto.Schema

  schema "official_shifts" do
    field :volunteer_name, :string
    field :role, :string
    field :shift_time, :string
    field :age_group, :string
    field :code, :string
  end
end

defmodule LastMinuteSignups do
  use Ecto.Schema

  schema "last_minute_signups" do
    field :volunteer_name, :string
    field :assigned_task, :string
    field :time_slot, :string
  end
end

Query

# from(o in OfficialShifts, select: map(o, [:volunteer_name, :role, :shift_time]))
# from(l in LastMinuteSignups, select: map(l, [:volunteer_name, :assigned_task, :time_slot]))
merged =
  from(
    o in OfficialShifts,
    full_join: l in LastMinuteSignups,
    on: o.volunteer_name == l.volunteer_name,
    select: %{
      volunteer: coalesce(o.volunteer_name, l.volunteer_name),
      role: coalesce(o.role, l.assigned_task),
      shift: coalesce(o.shift_time, l.time_slot)
    }
  )

from(
  m in subquery(merged),
  distinct: true,
  order_by: m.volunteer,
  select: [
    volunteer: m.volunteer,
    role:
      fragment("""
        CASE
            WHEN role ILIKE '%stage%' THEN 'Stage Setup'
            WHEN role ILIKE '%cocoa%' THEN 'Cocoa Station'
            WHEN role ILIKE '%park%' THEN 'Parking Support'
            WHEN role ILIKE '%choir%' THEN 'Choir Assistant'
            WHEN role ILIKE '%shovel%' THEN 'Snow Shoveling'
            WHEN role ILIKE '%hand%' THEN 'Handwarmer Handout'
            WHEN TRUE THEN CONCAT('UNCAUGHT_ROLE: ', role)
            END
      """),
    shift:
      fragment("""
        CASE
            WHEN shift ILIKE '10%am%' THEN '10:00 AM'
            WHEN shift ILIKE 'noon' THEN '12:00 PM'
            WHEN shift ILIKE '12%pm%' THEN '12:00 PM'
            WHEN shift ILIKE '2%pm%' THEN '2:00 PM'
            WHEN TRUE THEN CONCAT('UNCAUGHT_SHIFT_TIME: ', shift)
            END    
      """)
  ]
)
|> Repo.all()
|> Kino.DataTable.new()