Powered by AppSignal & Oban Pro

Day 10

2025/day10/day10.livemd

Day 10

# Configure postgrex to use the build-in JSON library before it's compiled
Application.put_env(:postgrex, :json_library, JSON)

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

Kino.configure(inspect: [charlists: :as_lists])

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 Delivery do
  use Ecto.Schema

  schema "deliveries" do
    field :child_name, :string
    field :delivery_location, :string
    field :gift_name, :string
    field :scheduled_at, :naive_datetime
  end
end

defmodule MisdeliveredPresent do
  use Ecto.Schema

  schema "misdelivered_presents" do
    field :child_name, :string
    field :delivery_location, :string
    field :gift_name, :string
    field :scheduled_at, :naive_datetime
    field :flagged_at, :naive_datetime
    field :reason, :string
  end
end

Query

from(d in Delivery)
|> Repo.aggregate(:count)
from(m in MisdeliveredPresent)
|> Repo.aggregate(:count)
# from(d in Delivery)
# from(m in MisdeliveredPresent)
# |> Repo.all()

invalid =
  from(
    d in Delivery,
    where:
      d.delivery_location in [
        "Volcano Rim",
        "Drifting Igloo",
        "Abandoned Lighthouse",
        "The Vibes"
      ],
    select: d
  )

misdelivered = from(d in subquery(invalid),
  select: %{
    id: d.id,
    child_name: d.child_name,
    delivery_location: d.delivery_location,
    gift_name: d.gift_name,
    scheduled_at: d.scheduled_at,
    flagged_at: fragment("NOW()"),
    reason: "Invalid delivery location"
  }
)

# I don't see any way to do this in one query without using raw sql
{num_inserted, inserted} = Repo.insert_all(MisdeliveredPresent, misdelivered, returning: true)
{num_deleted, _deleted} = Repo.delete_all(invalid)

IO.puts("Inserted #{num_inserted}, deleted: #{num_deleted}")

inserted
|> Kino.DataTable.new()