defmodule BdfrBrowser.Post do use Ecto.Schema import Ecto.Query, only: [dynamic: 1, dynamic: 2, from: 2, having: 3] alias BdfrBrowser.{Comment, Subreddit} @primary_key {:id, :string, autogenerate: false} schema "posts" do field :title, :string field :selftext, :string field :url, :string field :permalink, :string field :author, :string field :upvote_ratio, :float field :posted_at, :utc_datetime field :filename, :string belongs_to :subreddit, Subreddit has_many :comments, Comment end def date_listing(subreddits) when is_list(subreddits) do subreddit_ids = for s <- subreddits, do: s.id from(p in __MODULE__, select: fragment("to_char(?, 'YYYY-MM')", p.posted_at), where: p.subreddit_id in ^subreddit_ids, distinct: true, order_by: [desc: fragment("to_char(?, 'YYYY-MM')", p.posted_at)] ) end def date_listing(subreddit) do from(p in __MODULE__, select: fragment("to_char(?, 'YYYY-MM')", p.posted_at), where: p.subreddit_id == ^subreddit.id, distinct: true, order_by: [desc: fragment("to_char(?, 'YYYY-MM')", p.posted_at)] ) end def during_month(subreddit, month_str) do {:ok, d} = Date.from_iso8601("#{month_str}-01") during_range(subreddit, Date.beginning_of_month(d), Date.end_of_month(d)) end def during_range(subreddits, start_date, end_date, sort_field \\ :posted_at) def during_range(subreddits, start_date, end_date, sort_field) when is_list(subreddits) do subreddit_ids = for s <- subreddits, do: s.id from(p in __MODULE__, left_join: c in assoc(p, :comments), join: s in assoc(p, :subreddit), select: %{ id: p.id, title: p.title, url: p.url, author: p.author, posted_at: p.posted_at, num_comments: selected_as(count(c.id), :num_comments), subreddit: s.name, date: fragment("to_char(?, 'YYYY-MM')", p.posted_at) }, where: p.subreddit_id in ^subreddit_ids and type(p.posted_at, :date) >= ^start_date and type(p.posted_at, :date) <= ^end_date, order_by: ^dynamic_sort(sort_field), group_by: [p.id, s.name] ) end def during_range(subreddit, start_date, end_date, sort_field) do from(p in __MODULE__, left_join: c in assoc(p, :comments), join: s in assoc(p, :subreddit), select: %{ id: p.id, title: p.title, url: p.url, author: p.author, posted_at: p.posted_at, num_comments: selected_as(count(c.id), :num_comments), subreddit: s.name, date: fragment("to_char(?, 'YYYY-MM')", p.posted_at) }, where: p.subreddit_id == ^subreddit.id and type(p.posted_at, :date) >= ^start_date and type(p.posted_at, :date) <= ^end_date, order_by: ^dynamic_sort(sort_field), group_by: [p.id, s.name] ) end def with_comments(query, more_than \\ 0) do having(query, [p, c, s], count(c.id) > ^more_than) end def get_full(id) do from(p in __MODULE__, where: p.id == ^id, preload: [ comments: ^from(c in Comment, where: is_nil(c.parent_id), order_by: [asc: c.posted_at], preload: [children: ^from(c1 in Comment, order_by: [asc: c1.posted_at])] ) ] ) end def by_author(author) do from(p in __MODULE__, left_join: c in assoc(p, :comments), join: s in assoc(p, :subreddit), select: %{ id: p.id, title: p.title, url: p.url, posted_at: p.posted_at, num_comments: count(c.id), subreddit: s.name, date: fragment("to_char(?, 'YYYY-MM')", p.posted_at) }, where: p.author == ^author, order_by: [desc: p.posted_at], group_by: [p.id, s.name] ) end def search(str), do: search(str, nil) def search(str, subreddits) when is_nil(subreddits) do from(p in __MODULE__, left_join: c in assoc(p, :comments), join: s in assoc(p, :subreddit), select: %{ id: p.id, title: p.title, url: p.url, author: p.author, posted_at: p.posted_at, num_comments: count(c.id), subreddit: s.name, date: fragment("to_char(?, 'YYYY-MM')", p.posted_at) }, where: fragment("? @@ websearch_to_tsquery('english', ?)", p.searchable_content, ^str) or fragment("? @@ websearch_to_tsquery('german', ?)", p.searchable_content, ^str), order_by: [desc: p.posted_at], group_by: [p.id, s.name] ) end def search(str, subreddits) when is_list(subreddits) do from(p in __MODULE__, left_join: c in assoc(p, :comments), join: s in assoc(p, :subreddit), select: %{ id: p.id, title: p.title, url: p.url, author: p.author, posted_at: p.posted_at, num_comments: count(c.id), subreddit: s.name, date: fragment("to_char(?, 'YYYY-MM')", p.posted_at) }, where: s.name in ^subreddits and (fragment("? @@ websearch_to_tsquery('english', ?)", p.searchable_content, ^str) or fragment("? @@ websearch_to_tsquery('german', ?)", p.searchable_content, ^str)), order_by: [desc: p.posted_at], group_by: [p.id, s.name] ) end defp dynamic_sort(:posted_at), do: [{:desc, dynamic([p], p.posted_at)}] defp dynamic_sort(:most_comments), do: dynamic(fragment("num_comments DESC")) end