I’ve got a side project to help me learn Elixir and I am trying to get a user’s streak of concurrent daily posts in a row. I was able to put together the postgres query and successfully understand it and run it. Now I’m stumped on how to translate that in Elixir using Ecto.
Here is the sql query that I’m able to run, and below that my attempt at the Elixir function to do the same.
WITH
-- This table contains all the distinct date
-- instances in the data set
dates(date) AS (
SELECT DISTINCT CAST(updated_at AS DATE)
FROM public.posts
WHERE user_id = 20
),
-- Generate "groups" of dates by subtracting the
-- date's row number (no gaps) from the date itself
-- (with potential gaps). Whenever there is a gap,
-- there will be a new group
groups AS (
SELECT
ROW_NUMBER() OVER (ORDER BY date) AS rn,
date + -ROW_NUMBER() OVER (ORDER BY date) * INTERVAL'1 day' AS grp,
date
FROM dates
)
SELECT
COUNT(*) AS consecutive_dates,
MIN(date) AS start_date,
MAX(date) AS end_date,
current_date < MAX(date) + 1 AS active
FROM groups
GROUP BY grp HAVING COUNT(*) > 1 -- must be more than 1 to be a streak
ORDER BY 1 DESC, 2 DESC
and the struggle into Elixir
def streaks_of_post(user_id) do
dates =
from(p in Post,
distinct: [desc: p.updated_at],
order_by: [p.updated_at]
)
group_dates =
from d in dates,
select:
{row_number() |> over(order_by: d.updated_at),
type(fragment(date_add(d.updated_at, -1, "day")), :naive_datetime), d.updated_at}
query = Repo.all(group_dates)
end
I have been able to piece together that the WITH
queries need to be separate in Ecto, so I’ve made those. I’m currently stuck on date + -ROW_NUMBER() OVER (ORDER BY date) * INTERVAL'1 day' AS grp,
Haven’t gotten to the actual query of consecutive dates with min / max yet. I’ve been using sql consecutive streak as a rough guide for the sql bits.
Any help or direction is very much appreciated.