mirror of
https://github.com/philomena-dev/philomena.git
synced 2025-01-19 14:17:59 +01:00
API cursor navigation
This commit is contained in:
parent
b45130f073
commit
1e3b3430fc
23 changed files with 292 additions and 85 deletions
146
lib/philomena_query/cursor.ex
Normal file
146
lib/philomena_query/cursor.ex
Normal file
|
@ -0,0 +1,146 @@
|
|||
defmodule PhilomenaQuery.Cursor do
|
||||
alias PhilomenaQuery.Search
|
||||
alias Philomena.Repo
|
||||
import Ecto.Query
|
||||
|
||||
@typedoc """
|
||||
The underlying cursor type, which contains the ordered sort field values
|
||||
of a document.
|
||||
"""
|
||||
@type cursor :: [integer() | binary() | boolean()]
|
||||
|
||||
@typedoc """
|
||||
A mapping of document IDs to cursors.
|
||||
"""
|
||||
@type cursor_map :: %{integer() => cursor()}
|
||||
|
||||
@doc """
|
||||
Execute search with optional input cursor, and return results as tuple of
|
||||
`{results, cursors}`.
|
||||
|
||||
## Example
|
||||
|
||||
iex> search_records(
|
||||
...> %{query: ..., sort: [%{created_at: :desc}, %{id: :desc}]}
|
||||
...> Image
|
||||
...> )
|
||||
{%Scrivener.Page{entries: [%Image{id: 1}, ...]},
|
||||
%{1 => [1325394000000, 1], ...}}
|
||||
|
||||
"""
|
||||
@spec search_records(Search.search_definition(), Search.queryable(), search_after :: term()) ::
|
||||
{Scrivener.Page.t(), cursor_map()}
|
||||
def search_records(search_definition, queryable, search_after) do
|
||||
search_definition = search_after_definition(search_definition, search_after)
|
||||
page = Search.search_records_with_hits(search_definition, queryable)
|
||||
|
||||
{records, cursors} =
|
||||
Enum.map_reduce(page, %{}, fn {record, hit}, cursors ->
|
||||
sort = Map.fetch!(hit, "sort")
|
||||
|
||||
{record, Map.put(cursors, record.id, sort)}
|
||||
end)
|
||||
|
||||
{Map.put(page, :entries, records), cursors}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Return page of records and cursors map based on sort.
|
||||
|
||||
## Example
|
||||
|
||||
iex> paginate(Forum, [page_size: 25], ["dis", 3], asc: :name, asc: :id)
|
||||
%{4 => ["Generals", 4]}
|
||||
|
||||
"""
|
||||
@spec paginate(
|
||||
Ecto.Query.t(),
|
||||
scrivener_opts :: any(),
|
||||
search_after :: term(),
|
||||
sorts :: Keyword.t()
|
||||
) :: {Scrivener.Page.t(), cursor_map()}
|
||||
def paginate(query, pagination, search_after, sorts) do
|
||||
total_entries = Repo.aggregate(query, :count)
|
||||
pagination = Keyword.merge(pagination, options: [total_entries: total_entries])
|
||||
|
||||
records =
|
||||
query
|
||||
|> order_by(^sorts)
|
||||
|> search_after_query(search_after, sorts)
|
||||
|> Repo.paginate(pagination)
|
||||
|
||||
fields = Keyword.values(sorts)
|
||||
|
||||
cursors =
|
||||
Enum.reduce(records, %{}, fn record, cursors ->
|
||||
field_values = Enum.map(fields, &Map.fetch!(record, &1))
|
||||
Map.put(cursors, record.id, field_values)
|
||||
end)
|
||||
|
||||
{records, cursors}
|
||||
end
|
||||
|
||||
@spec search_after_definition(Search.search_definition(), term()) :: Search.search_definition()
|
||||
defp search_after_definition(search_definition, search_after) do
|
||||
search_after
|
||||
|> permit_search_after()
|
||||
|> case do
|
||||
[] ->
|
||||
search_definition
|
||||
|
||||
search_after ->
|
||||
update_in(search_definition.body, &Map.put(&1, :search_after, search_after))
|
||||
end
|
||||
end
|
||||
|
||||
@spec search_after_query(Ecto.Query.t(), term(), Keyword.t()) :: Ecto.Query.t()
|
||||
defp search_after_query(query, search_after, sorts) do
|
||||
search_after = permit_search_after(search_after)
|
||||
combined = Enum.zip(sorts, search_after)
|
||||
|
||||
case combined do
|
||||
[_some | _rest] = values ->
|
||||
or_clauses = dynamic([], false)
|
||||
|
||||
{or_clauses, _} =
|
||||
Enum.reduce(values, {or_clauses, []}, fn {{sd, col}, value}, {next, equal_parts} ->
|
||||
# more specific column has next value
|
||||
and_clauses =
|
||||
if sd == :asc do
|
||||
dynamic([s], field(s, ^col) > ^value)
|
||||
else
|
||||
dynamic([s], field(s, ^col) < ^value)
|
||||
end
|
||||
|
||||
# and
|
||||
and_clauses =
|
||||
Enum.reduce(equal_parts, and_clauses, fn {col, value}, rest ->
|
||||
# less specific columns are equal
|
||||
dynamic([s], field(s, ^col) == ^value and ^rest)
|
||||
end)
|
||||
|
||||
{dynamic(^next or ^and_clauses), equal_parts ++ [{col, value}]}
|
||||
end)
|
||||
|
||||
where(query, ^or_clauses)
|
||||
|
||||
_ ->
|
||||
query
|
||||
end
|
||||
end
|
||||
|
||||
# Validate that search_after values are only strings, numbers, and bools
|
||||
defp permit_search_after(search_after) do
|
||||
search_after
|
||||
|> permit_list()
|
||||
|> Enum.flat_map(&permit_value/1)
|
||||
end
|
||||
|
||||
defp permit_list(value) when is_list(value), do: value
|
||||
defp permit_list(_value), do: []
|
||||
|
||||
defp permit_value(value) when is_binary(value) or is_number(value) or is_boolean(value),
|
||||
do: [value]
|
||||
|
||||
defp permit_value(_value), do: []
|
||||
end
|
|
@ -2,18 +2,21 @@ defmodule PhilomenaWeb.Api.Json.Filter.SystemFilterController do
|
|||
use PhilomenaWeb, :controller
|
||||
|
||||
alias Philomena.Filters.Filter
|
||||
alias Philomena.Repo
|
||||
alias PhilomenaQuery.Cursor
|
||||
import Ecto.Query
|
||||
|
||||
def index(conn, _params) do
|
||||
system_filters =
|
||||
def index(conn, params) do
|
||||
{system_filters, cursors} =
|
||||
Filter
|
||||
|> where(system: true)
|
||||
|> order_by(asc: :id)
|
||||
|> Repo.paginate(conn.assigns.scrivener)
|
||||
|> Cursor.paginate(conn.assigns.scrivener, params["search_after"], asc: :id)
|
||||
|
||||
conn
|
||||
|> put_view(PhilomenaWeb.Api.Json.FilterView)
|
||||
|> render("index.json", filters: system_filters, total: system_filters.total_entries)
|
||||
|> render("index.json",
|
||||
cursors: cursors,
|
||||
filters: system_filters,
|
||||
total: system_filters.total_entries
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,10 +2,10 @@ defmodule PhilomenaWeb.Api.Json.Filter.UserFilterController do
|
|||
use PhilomenaWeb, :controller
|
||||
|
||||
alias Philomena.Filters.Filter
|
||||
alias Philomena.Repo
|
||||
alias PhilomenaQuery.Cursor
|
||||
import Ecto.Query
|
||||
|
||||
def index(conn, _params) do
|
||||
def index(conn, params) do
|
||||
user = conn.assigns.current_user
|
||||
|
||||
case user do
|
||||
|
@ -15,15 +15,18 @@ defmodule PhilomenaWeb.Api.Json.Filter.UserFilterController do
|
|||
|> text("")
|
||||
|
||||
_ ->
|
||||
user_filters =
|
||||
{user_filters, cursors} =
|
||||
Filter
|
||||
|> where(user_id: ^user.id)
|
||||
|> order_by(asc: :id)
|
||||
|> Repo.paginate(conn.assigns.scrivener)
|
||||
|> Cursor.paginate(conn.assigns.scrivener, params["search_after"], asc: :id)
|
||||
|
||||
conn
|
||||
|> put_view(PhilomenaWeb.Api.Json.FilterView)
|
||||
|> render("index.json", filters: user_filters, total: user_filters.total_entries)
|
||||
|> render("index.json",
|
||||
cursors: cursors,
|
||||
filters: user_filters,
|
||||
total: user_filters.total_entries
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,39 +1,46 @@
|
|||
defmodule PhilomenaWeb.Api.Json.Forum.Topic.PostController do
|
||||
use PhilomenaWeb, :controller
|
||||
|
||||
alias Philomena.Topics.Topic
|
||||
alias Philomena.Posts.Post
|
||||
alias PhilomenaQuery.Cursor
|
||||
alias Philomena.Repo
|
||||
import Ecto.Query
|
||||
|
||||
def index(conn, %{
|
||||
"forum_id" => forum_id,
|
||||
"topic_id" => topic_id,
|
||||
"search_after" => search_after
|
||||
}) do
|
||||
topic = Repo.one!(topic_query(topic_id, forum_id))
|
||||
|
||||
{posts, cursors} =
|
||||
post_query(topic_id, forum_id)
|
||||
|> Cursor.paginate(conn.assigns.scrivener, search_after, asc: :topic_position)
|
||||
|
||||
render(conn, "index.json", cursors: cursors, posts: posts, total: topic.post_count)
|
||||
end
|
||||
|
||||
def index(conn, %{"forum_id" => forum_id, "topic_id" => topic_id}) do
|
||||
page = conn.assigns.pagination.page_number
|
||||
|
||||
posts =
|
||||
Post
|
||||
|> join(:inner, [p], _ in assoc(p, :topic))
|
||||
|> join(:inner, [_p, t], _ in assoc(t, :forum))
|
||||
|> where(destroyed_content: false)
|
||||
|> where([_p, t], t.hidden_from_users == false and t.slug == ^topic_id)
|
||||
|> where([_p, _t, f], f.access_level == "normal" and f.short_name == ^forum_id)
|
||||
|> where([p], p.topic_position >= ^(25 * (page - 1)) and p.topic_position < ^(25 * page))
|
||||
|> order_by(asc: :topic_position)
|
||||
|> preload([:user, :topic])
|
||||
|> preload([_p, t, _f], topic: t)
|
||||
|> Repo.all()
|
||||
topic = Repo.one!(topic_query(topic_id, forum_id))
|
||||
|
||||
render(conn, "index.json", posts: posts, total: hd(posts).topic.post_count)
|
||||
{posts, cursors} =
|
||||
post_query(topic_id, forum_id)
|
||||
|> where(
|
||||
[posts: p],
|
||||
p.topic_position >= ^(25 * (page - 1)) and p.topic_position < ^(25 * page)
|
||||
)
|
||||
|> Cursor.paginate([page_size: 25], [], asc: :topic_position)
|
||||
|
||||
render(conn, "index.json", cursors: cursors, posts: posts, total: topic.post_count)
|
||||
end
|
||||
|
||||
def show(conn, %{"forum_id" => forum_id, "topic_id" => topic_id, "id" => post_id}) do
|
||||
post =
|
||||
Post
|
||||
|> join(:inner, [p], _ in assoc(p, :topic))
|
||||
|> join(:inner, [_p, t], _ in assoc(t, :forum))
|
||||
post_query(forum_id, topic_id)
|
||||
|> where(id: ^post_id)
|
||||
|> where(destroyed_content: false)
|
||||
|> where([_p, t], t.hidden_from_users == false and t.slug == ^topic_id)
|
||||
|> where([_p, _t, f], f.access_level == "normal" and f.short_name == ^forum_id)
|
||||
|> preload([:user, :topic])
|
||||
|> Repo.one()
|
||||
|
||||
cond do
|
||||
|
@ -46,4 +53,27 @@ defmodule PhilomenaWeb.Api.Json.Forum.Topic.PostController do
|
|||
render(conn, "show.json", post: post)
|
||||
end
|
||||
end
|
||||
|
||||
defp topic_query(topic_id, forum_id) do
|
||||
Topic
|
||||
|> from(as: :topic)
|
||||
|> join(:inner, [topic: t], _ in assoc(t, :forum), as: :forum)
|
||||
|> topic_conditions(topic_id, forum_id)
|
||||
end
|
||||
|
||||
defp post_query(topic_id, forum_id) do
|
||||
Post
|
||||
|> from(as: :posts)
|
||||
|> join(:inner, [posts: p], _ in assoc(p, :topic), as: :topic)
|
||||
|> join(:inner, [topic: t], _ in assoc(t, :forum), as: :forum)
|
||||
|> topic_conditions(topic_id, forum_id)
|
||||
|> where([posts: p], p.destroyed_content == false)
|
||||
|> preload([:user])
|
||||
end
|
||||
|
||||
defp topic_conditions(queryable, topic_id, forum_id) do
|
||||
queryable
|
||||
|> where([topic: t], t.hidden_from_users == false and t.slug == ^topic_id)
|
||||
|> where([forum: f], f.access_level == "normal" and f.short_name == ^forum_id)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,20 +2,24 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicController do
|
|||
use PhilomenaWeb, :controller
|
||||
|
||||
alias Philomena.Topics.Topic
|
||||
alias PhilomenaQuery.Cursor
|
||||
alias Philomena.Repo
|
||||
import Ecto.Query
|
||||
|
||||
def index(conn, %{"forum_id" => id}) do
|
||||
topics =
|
||||
def index(conn, %{"forum_id" => id} = params) do
|
||||
{topics, cursors} =
|
||||
Topic
|
||||
|> join(:inner, [t], _ in assoc(t, :forum))
|
||||
|> where(hidden_from_users: false)
|
||||
|> where([_t, f], f.access_level == "normal" and f.short_name == ^id)
|
||||
|> order_by(desc: :sticky, desc: :last_replied_to_at)
|
||||
|> preload([:user])
|
||||
|> Repo.paginate(conn.assigns.scrivener)
|
||||
|> Cursor.paginate(conn.assigns.scrivener, params["search_after"],
|
||||
desc: :sticky,
|
||||
desc: :last_replied_to_at,
|
||||
desc: :slug
|
||||
)
|
||||
|
||||
render(conn, "index.json", topics: topics, total: topics.total_entries)
|
||||
render(conn, "index.json", cursors: cursors, topics: topics, total: topics.total_entries)
|
||||
end
|
||||
|
||||
def show(conn, %{"forum_id" => forum_id, "id" => id}) do
|
||||
|
@ -25,7 +29,6 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicController do
|
|||
|> where(slug: ^id)
|
||||
|> where(hidden_from_users: false)
|
||||
|> where([_t, f], f.access_level == "normal" and f.short_name == ^forum_id)
|
||||
|> order_by(desc: :sticky, desc: :last_replied_to_at)
|
||||
|> preload([:user])
|
||||
|> Repo.one()
|
||||
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
defmodule PhilomenaWeb.Api.Json.ForumController do
|
||||
use PhilomenaWeb, :controller
|
||||
|
||||
alias PhilomenaQuery.Cursor
|
||||
alias Philomena.Forums.Forum
|
||||
alias Philomena.Repo
|
||||
import Ecto.Query
|
||||
|
||||
def index(conn, _params) do
|
||||
forums =
|
||||
def index(conn, params) do
|
||||
{forums, cursors} =
|
||||
Forum
|
||||
|> where(access_level: "normal")
|
||||
|> order_by(asc: :name)
|
||||
|> Repo.paginate(conn.assigns.scrivener)
|
||||
|> Cursor.paginate(conn.assigns.scrivener, params["search_after"],
|
||||
asc: :name,
|
||||
asc: :short_name
|
||||
)
|
||||
|
||||
render(conn, forums: forums, total: forums.total_entries)
|
||||
render(conn, cursors: cursors, forums: forums, total: forums.total_entries)
|
||||
end
|
||||
|
||||
def show(conn, %{"id" => id}) do
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule PhilomenaWeb.Api.Json.Search.CommentController do
|
||||
use PhilomenaWeb, :controller
|
||||
|
||||
alias PhilomenaQuery.Cursor
|
||||
alias PhilomenaQuery.Search
|
||||
alias Philomena.Comments.Comment
|
||||
alias Philomena.Comments.Query
|
||||
|
@ -12,7 +13,7 @@ defmodule PhilomenaWeb.Api.Json.Search.CommentController do
|
|||
|
||||
case Query.compile(params["q"], user: user) do
|
||||
{:ok, query} ->
|
||||
comments =
|
||||
{comments, cursors} =
|
||||
Comment
|
||||
|> Search.search_definition(
|
||||
%{
|
||||
|
@ -27,15 +28,19 @@ defmodule PhilomenaWeb.Api.Json.Search.CommentController do
|
|||
}
|
||||
}
|
||||
},
|
||||
sort: %{posted_at: :desc}
|
||||
sort: [%{posted_at: :desc}, %{id: :desc}]
|
||||
},
|
||||
conn.assigns.pagination
|
||||
)
|
||||
|> Search.search_records(preload(Comment, [:image, :user]))
|
||||
|> Cursor.search_records(preload(Comment, [:image, :user]), params["search_after"])
|
||||
|
||||
conn
|
||||
|> put_view(PhilomenaWeb.Api.Json.CommentView)
|
||||
|> render("index.json", comments: comments, total: comments.total_entries)
|
||||
|> render("index.json",
|
||||
comments: comments,
|
||||
cursors: cursors,
|
||||
total: comments.total_entries
|
||||
)
|
||||
|
||||
{:error, msg} ->
|
||||
conn
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule PhilomenaWeb.Api.Json.Search.FilterController do
|
||||
use PhilomenaWeb, :controller
|
||||
|
||||
alias PhilomenaQuery.Cursor
|
||||
alias PhilomenaQuery.Search
|
||||
alias Philomena.Filters.Filter
|
||||
alias Philomena.Filters.Query
|
||||
|
@ -11,7 +12,7 @@ defmodule PhilomenaWeb.Api.Json.Search.FilterController do
|
|||
|
||||
case Query.compile(params["q"], user: user) do
|
||||
{:ok, query} ->
|
||||
filters =
|
||||
{filters, cursors} =
|
||||
Filter
|
||||
|> Search.search_definition(
|
||||
%{
|
||||
|
@ -36,11 +37,11 @@ defmodule PhilomenaWeb.Api.Json.Search.FilterController do
|
|||
},
|
||||
conn.assigns.pagination
|
||||
)
|
||||
|> Search.search_records(preload(Filter, [:user]))
|
||||
|> Cursor.search_records(preload(Filter, [:user]), params["search_after"])
|
||||
|
||||
conn
|
||||
|> put_view(PhilomenaWeb.Api.Json.FilterView)
|
||||
|> render("index.json", filters: filters, total: filters.total_entries)
|
||||
|> render("index.json", cursors: cursors, filters: filters, total: filters.total_entries)
|
||||
|
||||
{:error, msg} ->
|
||||
conn
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule PhilomenaWeb.Api.Json.Search.GalleryController do
|
||||
use PhilomenaWeb, :controller
|
||||
|
||||
alias PhilomenaQuery.Cursor
|
||||
alias PhilomenaQuery.Search
|
||||
alias Philomena.Galleries.Gallery
|
||||
alias Philomena.Galleries.Query
|
||||
|
@ -9,20 +10,24 @@ defmodule PhilomenaWeb.Api.Json.Search.GalleryController do
|
|||
def index(conn, params) do
|
||||
case Query.compile(params["q"]) do
|
||||
{:ok, query} ->
|
||||
galleries =
|
||||
{galleries, cursors} =
|
||||
Gallery
|
||||
|> Search.search_definition(
|
||||
%{
|
||||
query: query,
|
||||
sort: %{created_at: :desc}
|
||||
sort: [%{created_at: :desc}, %{id: :desc}]
|
||||
},
|
||||
conn.assigns.pagination
|
||||
)
|
||||
|> Search.search_records(preload(Gallery, [:creator]))
|
||||
|> Cursor.search_records(preload(Gallery, [:creator]), params["search_after"])
|
||||
|
||||
conn
|
||||
|> put_view(PhilomenaWeb.Api.Json.GalleryView)
|
||||
|> render("index.json", galleries: galleries, total: galleries.total_entries)
|
||||
|> render("index.json",
|
||||
cursors: cursors,
|
||||
galleries: galleries,
|
||||
total: galleries.total_entries
|
||||
)
|
||||
|
||||
{:error, msg} ->
|
||||
conn
|
||||
|
|
|
@ -2,7 +2,7 @@ defmodule PhilomenaWeb.Api.Json.Search.ImageController do
|
|||
use PhilomenaWeb, :controller
|
||||
|
||||
alias PhilomenaWeb.ImageLoader
|
||||
alias PhilomenaQuery.Search
|
||||
alias PhilomenaQuery.Cursor
|
||||
alias Philomena.Interactions
|
||||
alias Philomena.Images.Image
|
||||
import Ecto.Query
|
||||
|
@ -13,13 +13,14 @@ defmodule PhilomenaWeb.Api.Json.Search.ImageController do
|
|||
|
||||
case ImageLoader.search_string(conn, params["q"]) do
|
||||
{:ok, {images, _tags}} ->
|
||||
images = Search.search_records(images, queryable)
|
||||
{images, cursors} = Cursor.search_records(images, queryable, params["search_after"])
|
||||
interactions = Interactions.user_interactions(images, user)
|
||||
|
||||
conn
|
||||
|> put_view(PhilomenaWeb.Api.Json.ImageView)
|
||||
|> render("index.json",
|
||||
images: images,
|
||||
cursors: cursors,
|
||||
total: images.total_entries,
|
||||
interactions: interactions
|
||||
)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule PhilomenaWeb.Api.Json.Search.PostController do
|
||||
use PhilomenaWeb, :controller
|
||||
|
||||
alias PhilomenaQuery.Cursor
|
||||
alias PhilomenaQuery.Search
|
||||
alias Philomena.Posts.Post
|
||||
alias Philomena.Posts.Query
|
||||
|
@ -11,7 +12,7 @@ defmodule PhilomenaWeb.Api.Json.Search.PostController do
|
|||
|
||||
case Query.compile(params["q"], user: user) do
|
||||
{:ok, query} ->
|
||||
posts =
|
||||
{posts, cursors} =
|
||||
Post
|
||||
|> Search.search_definition(
|
||||
%{
|
||||
|
@ -24,15 +25,15 @@ defmodule PhilomenaWeb.Api.Json.Search.PostController do
|
|||
]
|
||||
}
|
||||
},
|
||||
sort: %{created_at: :desc}
|
||||
sort: [%{created_at: :desc}, %{id: :desc}]
|
||||
},
|
||||
conn.assigns.pagination
|
||||
)
|
||||
|> Search.search_records(preload(Post, [:user, :topic]))
|
||||
|> Cursor.search_records(preload(Post, [:user, :topic]), params["search_after"])
|
||||
|
||||
conn
|
||||
|> put_view(PhilomenaWeb.Api.Json.Forum.Topic.PostView)
|
||||
|> render("index.json", posts: posts, total: posts.total_entries)
|
||||
|> render("index.json", cursors: cursors, posts: posts, total: posts.total_entries)
|
||||
|
||||
{:error, msg} ->
|
||||
conn
|
||||
|
|
|
@ -29,6 +29,7 @@ defmodule PhilomenaWeb.Api.Json.Search.ReverseController do
|
|||
|> put_view(PhilomenaWeb.Api.Json.ImageView)
|
||||
|> render("index.json",
|
||||
images: images,
|
||||
cursors: %{},
|
||||
total: total,
|
||||
interactions: interactions
|
||||
)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule PhilomenaWeb.Api.Json.Search.TagController do
|
||||
use PhilomenaWeb, :controller
|
||||
|
||||
alias PhilomenaQuery.Cursor
|
||||
alias PhilomenaQuery.Search
|
||||
alias Philomena.Tags.Tag
|
||||
alias Philomena.Tags.Query
|
||||
|
@ -9,19 +10,20 @@ defmodule PhilomenaWeb.Api.Json.Search.TagController do
|
|||
def index(conn, params) do
|
||||
case Query.compile(params["q"]) do
|
||||
{:ok, query} ->
|
||||
tags =
|
||||
{tags, cursors} =
|
||||
Tag
|
||||
|> Search.search_definition(
|
||||
%{query: query, sort: %{images: :desc}},
|
||||
%{query: query, sort: [%{images: :desc}, %{id: :desc}]},
|
||||
conn.assigns.pagination
|
||||
)
|
||||
|> Search.search_records(
|
||||
preload(Tag, [:aliased_tag, :aliases, :implied_tags, :implied_by_tags, :dnp_entries])
|
||||
|> Cursor.search_records(
|
||||
preload(Tag, [:aliased_tag, :aliases, :implied_tags, :implied_by_tags, :dnp_entries]),
|
||||
params["search_after"]
|
||||
)
|
||||
|
||||
conn
|
||||
|> put_view(PhilomenaWeb.Api.Json.TagView)
|
||||
|> render("index.json", tags: tags, total: tags.total_entries)
|
||||
|> render("index.json", cursors: cursors, tags: tags, total: tags.total_entries)
|
||||
|
||||
{:error, msg} ->
|
||||
conn
|
||||
|
|
|
@ -80,7 +80,7 @@ defmodule PhilomenaWeb.ImageSorter do
|
|||
end
|
||||
|
||||
defp parse_sf(_params, sd, query) do
|
||||
%{query: query, sorts: [%{"first_seen_at" => sd}]}
|
||||
%{query: query, sorts: [%{"first_seen_at" => sd}, %{"id" => sd}]}
|
||||
end
|
||||
|
||||
defp random_query(seed, sd, query) do
|
||||
|
|
|
@ -2,8 +2,9 @@ defmodule PhilomenaWeb.Api.Json.CommentView do
|
|||
use PhilomenaWeb, :view
|
||||
alias PhilomenaWeb.UserAttributionView
|
||||
|
||||
def render("index.json", %{comments: comments, total: total} = assigns) do
|
||||
def render("index.json", %{cursors: cursors, comments: comments, total: total} = assigns) do
|
||||
%{
|
||||
cursors: cursors,
|
||||
comments: render_many(comments, PhilomenaWeb.Api.Json.CommentView, "comment.json", assigns),
|
||||
total: total
|
||||
}
|
||||
|
|
|
@ -1,17 +1,6 @@
|
|||
defmodule PhilomenaWeb.Api.Json.DnpView do
|
||||
use PhilomenaWeb, :view
|
||||
|
||||
def render("index.json", %{dnps: dnp, total: total} = assigns) do
|
||||
%{
|
||||
dnps: render_many(dnp, PhilomenaWeb.Api.Json.DnpView, "dnp.json", assigns),
|
||||
total: total
|
||||
}
|
||||
end
|
||||
|
||||
def render("show.json", %{dnp: dnp} = assigns) do
|
||||
%{dnp: render_one(dnp, PhilomenaWeb.Api.Json.DnpView, "dnp.json", assigns)}
|
||||
end
|
||||
|
||||
def render("dnp.json", %{dnp: dnp}) do
|
||||
%{
|
||||
id: dnp.id,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
defmodule PhilomenaWeb.Api.Json.FilterView do
|
||||
use PhilomenaWeb, :view
|
||||
|
||||
def render("index.json", %{filters: filters, total: total} = assigns) do
|
||||
def render("index.json", %{cursors: cursors, filters: filters, total: total} = assigns) do
|
||||
%{
|
||||
cursors: cursors,
|
||||
filters: render_many(filters, PhilomenaWeb.Api.Json.FilterView, "filter.json", assigns),
|
||||
total: total
|
||||
}
|
||||
|
|
|
@ -2,8 +2,9 @@ defmodule PhilomenaWeb.Api.Json.Forum.Topic.PostView do
|
|||
use PhilomenaWeb, :view
|
||||
alias PhilomenaWeb.UserAttributionView
|
||||
|
||||
def render("index.json", %{posts: posts, total: total} = assigns) do
|
||||
def render("index.json", %{cursors: cursors, posts: posts, total: total} = assigns) do
|
||||
%{
|
||||
cursors: cursors,
|
||||
posts: render_many(posts, PhilomenaWeb.Api.Json.Forum.Topic.PostView, "post.json", assigns),
|
||||
total: total
|
||||
}
|
||||
|
|
|
@ -2,8 +2,9 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicView do
|
|||
use PhilomenaWeb, :view
|
||||
alias PhilomenaWeb.UserAttributionView
|
||||
|
||||
def render("index.json", %{topics: topics, total: total} = assigns) do
|
||||
def render("index.json", %{cursors: cursors, topics: topics, total: total} = assigns) do
|
||||
%{
|
||||
cursors: cursors,
|
||||
topics: render_many(topics, PhilomenaWeb.Api.Json.Forum.TopicView, "topic.json", assigns),
|
||||
total: total
|
||||
}
|
||||
|
@ -15,6 +16,7 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicView do
|
|||
|
||||
def render("topic.json", %{topic: %{hidden_from_users: true}}) do
|
||||
%{
|
||||
id: nil,
|
||||
slug: nil,
|
||||
title: nil,
|
||||
post_count: nil,
|
||||
|
@ -29,6 +31,7 @@ defmodule PhilomenaWeb.Api.Json.Forum.TopicView do
|
|||
|
||||
def render("topic.json", %{topic: topic}) do
|
||||
%{
|
||||
id: topic.id,
|
||||
slug: topic.slug,
|
||||
title: topic.title,
|
||||
post_count: topic.post_count,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
defmodule PhilomenaWeb.Api.Json.ForumView do
|
||||
use PhilomenaWeb, :view
|
||||
|
||||
def render("index.json", %{forums: forums, total: total} = assigns) do
|
||||
def render("index.json", %{cursors: cursors, forums: forums, total: total} = assigns) do
|
||||
%{
|
||||
cursors: cursors,
|
||||
forums: render_many(forums, PhilomenaWeb.Api.Json.ForumView, "forum.json", assigns),
|
||||
total: total
|
||||
}
|
||||
|
@ -14,6 +15,7 @@ defmodule PhilomenaWeb.Api.Json.ForumView do
|
|||
|
||||
def render("forum.json", %{forum: %{access_level: "normal"} = forum}) do
|
||||
%{
|
||||
id: forum.id,
|
||||
name: forum.name,
|
||||
short_name: forum.short_name,
|
||||
description: forum.description,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
defmodule PhilomenaWeb.Api.Json.GalleryView do
|
||||
use PhilomenaWeb, :view
|
||||
|
||||
def render("index.json", %{galleries: galleries, total: total} = assigns) do
|
||||
def render("index.json", %{cursors: cursors, galleries: galleries, total: total} = assigns) do
|
||||
%{
|
||||
cursors: cursors,
|
||||
galleries:
|
||||
render_many(galleries, PhilomenaWeb.Api.Json.GalleryView, "gallery.json", assigns),
|
||||
total: total
|
||||
|
|
|
@ -2,8 +2,12 @@ defmodule PhilomenaWeb.Api.Json.ImageView do
|
|||
use PhilomenaWeb, :view
|
||||
alias PhilomenaWeb.ImageView
|
||||
|
||||
def render("index.json", %{images: images, interactions: interactions, total: total} = assigns) do
|
||||
def render(
|
||||
"index.json",
|
||||
%{cursors: cursors, images: images, interactions: interactions, total: total} = assigns
|
||||
) do
|
||||
%{
|
||||
cursors: cursors,
|
||||
images: render_many(images, PhilomenaWeb.Api.Json.ImageView, "image.json", assigns),
|
||||
interactions: interactions,
|
||||
total: total
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
defmodule PhilomenaWeb.Api.Json.TagView do
|
||||
use PhilomenaWeb, :view
|
||||
|
||||
def render("index.json", %{tags: tags, total: total} = assigns) do
|
||||
def render("index.json", %{cursors: cursors, tags: tags, total: total} = assigns) do
|
||||
%{
|
||||
cursors: cursors,
|
||||
tags: render_many(tags, PhilomenaWeb.Api.Json.TagView, "tag.json", assigns),
|
||||
total: total
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue