From 0f3cb295a35913c4d7e1895a79e55b58edf022a6 Mon Sep 17 00:00:00 2001 From: "byte[]" Date: Mon, 30 Dec 2019 16:02:25 -0500 Subject: [PATCH] break compile time dependencies in query compilers --- lib/philomena/comments/query.ex | 121 +++++++++--------------- lib/philomena/galleries/query.ex | 33 +++---- lib/philomena/images/query.ex | 153 ++++++++++++------------------- lib/philomena/posts/query.ex | 111 +++++++++------------- lib/philomena/reports/query.ex | 32 +++---- lib/philomena/tags/query.ex | 39 ++++---- 6 files changed, 193 insertions(+), 296 deletions(-) diff --git a/lib/philomena/comments/query.ex b/lib/philomena/comments/query.ex index 8d4f504e..c2e5c989 100644 --- a/lib/philomena/comments/query.ex +++ b/lib/philomena/comments/query.ex @@ -1,7 +1,7 @@ defmodule Philomena.Comments.Query do alias Search.Parser - def user_id_transform(_ctx, data) do + defp user_id_transform(_ctx, data) do case Integer.parse(data) do {int, _rest} -> { @@ -21,7 +21,7 @@ defmodule Philomena.Comments.Query do end end - def author_transform(_ctx, data) do + defp author_transform(_ctx, data) do { :ok, %{ @@ -35,85 +35,54 @@ defmodule Philomena.Comments.Query do } end - def user_my_transform(%{user: %{id: id}}, "comments"), + defp user_my_transform(%{user: %{id: id}}, "comments"), do: {:ok, %{term: %{user_id: id}}} - def user_my_transform(_ctx, _value), + defp user_my_transform(_ctx, _value), do: {:error, "Unknown `my' value."} - int_fields = ~W(id) - date_fields = ~W(created_at) - literal_fields = ~W(image_id) - ngram_fields = ~W(body) - custom_fields = ~W(author user_id) - default_field = {"body", :ngram} - transforms = %{ - "user_id" => &Philomena.Comments.Query.user_id_transform/2, - "author" => &Philomena.Comments.Query.author_transform/2 - } - aliases = %{ - "created_at" => "posted_at", - } - - user_custom = custom_fields ++ ~W(my) - user_transforms = Map.merge(transforms, %{ - "my" => &Philomena.Comments.Query.user_my_transform/2 - }) - - mod_literal_fields = ~W(image_id user_id author fingerprint) - mod_ip_fields = ~W(ip) - mod_bool_fields = ~W(anonymous deleted) - mod_aliases = Map.merge(aliases, %{ - "deleted" => "hidden_from_users" - }) - mod_custom = user_custom -- ~W(author user_id) - mod_transforms = Map.drop(user_transforms, ["user_id", "author"]) - - @anonymous_parser Parser.parser( - int_fields: int_fields, - date_fields: date_fields, - literal_fields: literal_fields, - ngram_fields: ngram_fields, - custom_fields: custom_fields, - aliases: aliases, - default_field: default_field, - transforms: transforms - ) - - @user_parser Parser.parser( - int_fields: int_fields, - date_fields: date_fields, - literal_fields: literal_fields, - ngram_fields: ngram_fields, - custom_fields: user_custom, - transforms: user_transforms, - aliases: aliases, - default_field: default_field - ) - - @moderator_parser Parser.parser( - int_fields: int_fields, - date_fields: date_fields, - literal_fields: mod_literal_fields, - ip_fields: mod_ip_fields, - ngram_fields: ngram_fields, - bool_fields: mod_bool_fields, - custom_fields: mod_custom, - transforms: mod_transforms, - aliases: mod_aliases, - default_field: default_field - ) - - def parse_anonymous(context, query_string) do - Parser.parse(@anonymous_parser, query_string, context) + defp anonymous_fields do + [ + int_fields: ~W(id), + date_fields: ~W(created_at), + literal_fields: ~W(image_id), + ngram_fields: ~W(body), + custom_fields: ~W(author user_id), + default_field: {"body", :ngram}, + transforms: %{ + "user_id" => &user_id_transform/2, + "author" => &author_transform/2 + }, + aliases: %{"created_at" => "posted_at"} + ] end - def parse_user(context, query_string) do - Parser.parse(@user_parser, query_string, context) + defp user_fields do + fields = anonymous_fields() + + Keyword.merge(fields, [ + custom_fields: fields[:custom_fields] ++ ~W(my), + transforms: Map.merge(fields[:transforms], %{"my" => &user_my_transform/2}) + ]) end - def parse_moderator(context, query_string) do - Parser.parse(@moderator_parser, query_string, context) + defp moderator_fields do + fields = user_fields() + + Keyword.merge(fields, [ + literal_fields: ~W(image_id user_id author fingerprint), + ip_fields: ~W(ip), + bool_fields: ~W(anonymous deleted), + custom_fields: fields[:custom_fields] -- ~W(author user_id), + aliases: Map.merge(fields[:aliases], %{"deleted" => "hidden_from_users"}), + transforms: Map.drop(fields[:transforms], ~W(author user_id)) + ]) + end + + defp parse(fields, context, query_string) do + fields + |> Parser.parser() + |> Parser.parse(query_string, context) end def compile(user, query_string) do @@ -121,13 +90,13 @@ defmodule Philomena.Comments.Query do case user do nil -> - parse_anonymous(%{user: nil}, query_string) + parse(anonymous_fields(), %{user: nil}, query_string) %{role: role} when role in ~W(user assistant) -> - parse_user(%{user: user}, query_string) + parse(user_fields(), %{user: user}, query_string) %{role: role} when role in ~W(moderator admin) -> - parse_moderator(%{user: user}, query_string) + parse(moderator_fields(), %{user: user}, query_string) _ -> raise ArgumentError, "Unknown user role." diff --git a/lib/philomena/galleries/query.ex b/lib/philomena/galleries/query.ex index 97c6bc1b..71827d5f 100644 --- a/lib/philomena/galleries/query.ex +++ b/lib/philomena/galleries/query.ex @@ -1,27 +1,24 @@ defmodule Philomena.Galleries.Query do alias Search.Parser - int_fields = ~W(id image_count watcher_count) - literal_fields = ~W(title user image_ids watcher_ids) - date_fields = ~W(created_at updated_at) - ngram_fields = ~W(description) - default_field = {"title", :term} - aliases = %{ - "user" => "creator" - } - - @gallery_parser Parser.parser( - int_fields: int_fields, - literal_fields: literal_fields, - date_fields: date_fields, - ngram_fields: ngram_fields, - default_field: default_field, - aliases: aliases - ) + defp fields do + [ + int_fields: ~W(id image_count watcher_count), + literal_fields: ~W(title user image_ids watcher_ids), + date_fields: ~W(created_at updated_at), + ngram_fields: ~W(description), + default_field: {"title", :term}, + aliases: %{ + "user" => "creator" + } + ] + end def compile(query_string) do query_string = query_string || "" - Parser.parse(@gallery_parser, query_string) + fields() + |> Parser.parser() + |> Parser.parse(query_string) end end diff --git a/lib/philomena/images/query.ex b/lib/philomena/images/query.ex index 8e909b6e..54de4913 100644 --- a/lib/philomena/images/query.ex +++ b/lib/philomena/images/query.ex @@ -2,28 +2,28 @@ defmodule Philomena.Images.Query do alias Search.Parser alias Philomena.Repo - def gallery_id_transform(_ctx, value), + defp gallery_id_transform(_ctx, value), do: {:ok, %{nested: %{path: :galleries, query: %{term: %{"galleries.id" => value}}}}} - def user_my_transform(%{user: %{id: id}}, "faves"), + defp user_my_transform(%{user: %{id: id}}, "faves"), do: {:ok, %{term: %{favourited_by_user_ids: id}}} - def user_my_transform(%{user: %{id: id}}, "upvotes"), + defp user_my_transform(%{user: %{id: id}}, "upvotes"), do: {:ok, %{term: %{upvoter_ids: id}}} - def user_my_transform(%{user: %{id: id}}, "downvotes"), + defp user_my_transform(%{user: %{id: id}}, "downvotes"), do: {:ok, %{term: %{downvoter_ids: id}}} - def user_my_transform(%{user: %{id: id}}, "uploads"), + defp user_my_transform(%{user: %{id: id}}, "uploads"), do: {:ok, %{term: %{true_uploader_id: id}}} - def user_my_transform(%{user: %{id: id}}, "hidden"), + defp user_my_transform(%{user: %{id: id}}, "hidden"), do: {:ok, %{term: %{hidden_by_user_ids: id}}} - def user_my_transform(%{watch: true}, "watched"), + defp user_my_transform(%{watch: true}, "watched"), do: {:error, "Recursive watchlists are not allowed."} - def user_my_transform(%{user: user} = ctx, "watched") do + defp user_my_transform(%{user: user} = ctx, "watched") do ctx = Map.merge(ctx, %{watch: true}) tag_include = %{terms: %{tag_ids: user.watched_tag_ids}} @@ -49,101 +49,66 @@ defmodule Philomena.Images.Query do {:ok, %{bool: %{should: should, must_not: must_not}}} end - def user_my_transform(_ctx, _value), + defp user_my_transform(_ctx, _value), do: {:error, "Unknown `my' value."} defp invalid_filter_guard(ctx, search_string) do - case Philomena.Images.Query.parse_user(ctx, Search.String.normalize(search_string)) do + case parse(user_fields(), ctx, Search.String.normalize(search_string)) do {:ok, query} -> query _error -> %{match_all: %{}} end end - int_fields = ~W(id width height comment_count score upvotes downvotes faves uploader_id faved_by_id tag_count) - float_fields = ~W(aspect_ratio wilson_score) - date_fields = ~W(created_at updated_at first_seen_at) - literal_fields = ~W(faved_by orig_sha512_hash sha512_hash uploader source_url original_format) - ngram_fields = ~W(description) - custom_fields = ~W(gallery_id) - default_field = {"namespaced_tags.name", :term} - transforms = %{ - "gallery_id" => &Philomena.Images.Query.gallery_id_transform/2 - } - aliases = %{ - "faved_by" => "favourited_by_users", - "faved_by_id" => "favourited_by_user_ids" - } - - - user_custom = custom_fields ++ ~W(my) - user_transforms = Map.merge(transforms, %{ - "my" => &Philomena.Images.Query.user_my_transform/2 - }) - - - mod_int_fields = int_fields ++ ~W(upvoted_by_id downvoted_by_id true_uploader_id hidden_by_id deleted_by_user_id) - mod_literal_fields = literal_fields ++ ~W(fingerprint upvoted_by downvoted_by true_uploader hidden_by deleted_by_user) - mod_ip_fields = ~W(ip) - mod_bool_fields = ~W(deleted) - mod_aliases = Map.merge(aliases, %{ - "upvoted_by" => "upvoters", - "downvoted_by" => "downvoters", - "upvoted_by_id" => "upvoter_ids", - "downvoted_by_id" => "downvoter_ids", - "hidden_by" => "hidden_by_users", - "hidden_by_id" => "hidden_by_user_ids", - "deleted" => "hidden_from_users" - }) - - - @anonymous_parser Parser.parser( - int_fields: int_fields, - float_fields: float_fields, - date_fields: date_fields, - literal_fields: literal_fields, - ngram_fields: ngram_fields, - custom_fields: custom_fields, - transforms: transforms, - aliases: aliases, - default_field: default_field - ) - - @user_parser Parser.parser( - int_fields: int_fields, - float_fields: float_fields, - date_fields: date_fields, - literal_fields: literal_fields, - ngram_fields: ngram_fields, - custom_fields: user_custom, - transforms: user_transforms, - aliases: aliases, - default_field: default_field - ) - - @moderator_parser Parser.parser( - int_fields: mod_int_fields, - float_fields: float_fields, - date_fields: date_fields, - literal_fields: mod_literal_fields, - ip_fields: mod_ip_fields, - ngram_fields: ngram_fields, - bool_fields: mod_bool_fields, - custom_fields: user_custom, - transforms: user_transforms, - aliases: mod_aliases, - default_field: default_field - ) - - def parse_anonymous(context, query_string) do - Parser.parse(@anonymous_parser, query_string, context) + defp anonymous_fields do + [ + int_fields: ~W(id width height comment_count score upvotes downvotes faves uploader_id faved_by_id tag_count), + float_fields: ~W(aspect_ratio wilson_score), + date_fields: ~W(created_at updated_at first_seen_at), + literal_fields: ~W(faved_by orig_sha512_hash sha512_hash uploader source_url original_format), + ngram_fields: ~W(description), + custom_fields: ~W(gallery_id), + default_field: {"namespaced_tags.name", :term}, + transforms: %{"gallery_id" => &gallery_id_transform/2}, + aliases: %{ + "faved_by" => "favourited_by_users", + "faved_by_id" => "favourited_by_user_ids" + } + ] end - def parse_user(context, query_string) do - Parser.parse(@user_parser, query_string, context) + defp user_fields do + fields = anonymous_fields() + + Keyword.merge(fields, [ + custom_fields: fields[:custom_fields] ++ ~W(my), + transforms: Map.merge(fields[:transforms], %{"my" => &user_my_transform/2}) + ]) end - def parse_moderator(context, query_string) do - Parser.parse(@moderator_parser, query_string, context) + defp moderator_fields do + fields = user_fields() + + Keyword.merge(fields, [ + int_fields: fields[:int_fields] ++ ~W(upvoted_by_id downvoted_by_id true_uploader_id hidden_by_id deleted_by_user_id), + literal_fields: fields[:literal_fields] ++ ~W(fingerprint upvoted_by downvoted_by true_uploader hidden_by deleted_by_user), + ip_fields: ~W(ip), + bool_fields: ~W(deleted), + aliases: Map.merge(fields[:aliases], %{ + "upvoted_by" => "upvoters", + "downvoted_by" => "downvoters", + "upvoted_by_id" => "upvoter_ids", + "downvoted_by_id" => "downvoter_ids", + "hidden_by" => "hidden_by_users", + "hidden_by_id" => "hidden_by_user_ids", + "deleted" => "hidden_from_users" + }) + ]) + end + + defp parse(fields, context, query_string) do + fields + |> Parser.parser() + |> Parser.parse(query_string, context) end def compile(user, query_string, watch \\ false) do @@ -151,13 +116,13 @@ defmodule Philomena.Images.Query do case user do nil -> - parse_anonymous(%{user: nil, watch: watch}, query_string) + parse(anonymous_fields(), %{user: nil, watch: watch}, query_string) %{role: role} when role in ~W(user assistant) -> - parse_user(%{user: user, watch: watch}, query_string) + parse(user_fields(), %{user: user, watch: watch}, query_string) %{role: role} when role in ~W(moderator admin) -> - parse_moderator(%{user: user, watch: watch}, query_string) + parse(moderator_fields(), %{user: user, watch: watch}, query_string) _ -> raise ArgumentError, "Unknown user role." diff --git a/lib/philomena/posts/query.ex b/lib/philomena/posts/query.ex index a0f65577..9eef61f4 100644 --- a/lib/philomena/posts/query.ex +++ b/lib/philomena/posts/query.ex @@ -1,7 +1,7 @@ defmodule Philomena.Posts.Query do alias Search.Parser - def user_id_transform(_ctx, data) do + defp user_id_transform(_ctx, data) do case Integer.parse(data) do {int, _rest} -> { @@ -21,7 +21,7 @@ defmodule Philomena.Posts.Query do end end - def author_transform(_ctx, data) do + defp author_transform(_ctx, data) do { :ok, %{ @@ -35,77 +35,52 @@ defmodule Philomena.Posts.Query do } end - def user_my_transform(%{user: %{id: id}}, "posts"), + defp user_my_transform(%{user: %{id: id}}, "posts"), do: {:ok, %{term: %{user_id: id}}} - def user_my_transform(_ctx, _value), + defp user_my_transform(_ctx, _value), do: {:error, "Unknown `my' value."} - int_fields = ~W(id) - date_fields = ~W(created_at updated_at) - literal_fields = ~W(forum_id topic_id) - ngram_fields = ~W(body subject) - custom_fields = ~W(author user_id) - default_field = {"body", :ngram} - transforms = %{ - "user_id" => &Philomena.Posts.Query.user_id_transform/2, - "author" => &Philomena.Posts.Query.author_transform/2 - } - - user_custom = custom_fields ++ ~W(my) - user_transforms = Map.merge(transforms, %{ - "my" => &Philomena.Posts.Query.user_my_transform/2 - }) - - mod_literal_fields = ~W(forum_id topic_id user_id author fingerprint) - mod_ip_fields = ~W(ip) - mod_bool_fields = ~W(anonymous deleted) - mod_custom = user_custom -- ~W(author user_id) - mod_transforms = Map.drop(user_transforms, ["user_id", "author"]) - - - @anonymous_parser Parser.parser( - int_fields: int_fields, - date_fields: date_fields, - literal_fields: literal_fields, - ngram_fields: ngram_fields, - custom_fields: custom_fields, - default_field: default_field, - transforms: transforms - ) - - @user_parser Parser.parser( - int_fields: int_fields, - date_fields: date_fields, - literal_fields: literal_fields, - ngram_fields: ngram_fields, - custom_fields: user_custom, - transforms: user_transforms, - default_field: default_field - ) - - @moderator_parser Parser.parser( - int_fields: int_fields, - date_fields: date_fields, - literal_fields: mod_literal_fields, - ip_fields: mod_ip_fields, - ngram_fields: ngram_fields, - bool_fields: mod_bool_fields, - custom_fields: mod_custom, - transforms: mod_transforms, - default_field: default_field - ) - - def parse_anonymous(context, query_string) do - Parser.parse(@anonymous_parser, query_string, context) + defp anonymous_fields do + [ + int_fields: ~W(id), + date_fields: ~W(created_at updated_at), + literal_fields: ~W(forum_id topic_id), + ngram_fields: ~W(body subject), + custom_fields: ~W(author user_id), + default_field: {"body", :ngram}, + transforms: %{ + "user_id" => &user_id_transform/2, + "author" => &author_transform/2 + } + ] end - def parse_user(context, query_string) do - Parser.parse(@user_parser, query_string, context) + defp user_fields do + fields = anonymous_fields() + + Keyword.merge(fields, [ + custom_fields: fields[:custom_fields] ++ ~W(my), + transforms: Map.merge(fields[:transforms], %{"my" => &user_my_transform/2}) + ]) end - def parse_moderator(context, query_string) do - Parser.parse(@moderator_parser, query_string, context) + defp moderator_fields do + fields = user_fields() + + Keyword.merge(fields, [ + literal_fields: ~W(forum_id topic_id user_id author fingerprint), + ip_fields: ~W(ip), + bool_fields: ~W(anonymous deleted), + custom_fields: fields[:custom_fields] -- ~W(author user_id), + transforms: Map.drop(fields[:transforms], ["user_id", "author"]) + ]) + end + + defp parse(fields, context, query_string) do + fields + |> Parser.parser() + |> Parser.parse(query_string, context) end def compile(user, query_string) do @@ -113,13 +88,13 @@ defmodule Philomena.Posts.Query do case user do nil -> - parse_anonymous(%{user: nil}, query_string) + parse(anonymous_fields(), %{user: nil}, query_string) %{role: role} when role in ~W(user assistant) -> - parse_user(%{user: user}, query_string) + parse(user_fields(), %{user: user}, query_string) %{role: role} when role in ~W(moderator admin) -> - parse_moderator(%{user: user}, query_string) + parse(moderator_fields(), %{user: user}, query_string) _ -> raise ArgumentError, "Unknown user role." diff --git a/lib/philomena/reports/query.ex b/lib/philomena/reports/query.ex index 6fd8d4db..905a17f0 100644 --- a/lib/philomena/reports/query.ex +++ b/lib/philomena/reports/query.ex @@ -1,25 +1,21 @@ defmodule Philomena.Reports.Query do alias Search.Parser - int_fields = ~W(id image_id) - date_fields = ~W(created_at) - literal_fields = ~W(state user user_id admin admin_id reportable_type reportable_id fingerprint) - ip_fields = ~W(ip) - bool_fields = ~W(open) - ngram_fields = ~W(reason) - default_field = {"reason", :ngram} - - @parser Parser.parser( - int_fields: int_fields, - date_fields: date_fields, - literal_fields: literal_fields, - ip_fields: ip_fields, - bool_fields: bool_fields, - ngram_fields: ngram_fields, - default_field: default_field - ) + defp fields do + [ + int_fields: ~W(id image_id), + date_fields: ~W(created_at), + literal_fields: ~W(state user user_id admin admin_id reportable_type reportable_id fingerprint), + ip_fields: ~W(ip), + bool_fields: ~W(open), + ngram_fields: ~W(reason), + default_field: {"reason", :ngram} + ] + end def compile(query_string) do - Parser.parse(@parser, query_string || "", %{}) + fields() + |> Parser.parser() + |> Parser.parse(query_string || "", %{}) end end diff --git a/lib/philomena/tags/query.ex b/lib/philomena/tags/query.ex index 5b677cef..849daa57 100644 --- a/lib/philomena/tags/query.ex +++ b/lib/philomena/tags/query.ex @@ -1,29 +1,24 @@ defmodule Philomena.Tags.Query do alias Search.Parser - int_fields = ~W(id images) - literal_fields = ~W(slug name name_in_namespace namespace implies alias_of implied_by aliases category analyzed_name) - bool_fields = ~W(aliased) - ngram_fields = ~W(description short_description) - default_field = {"analyzed_name", :ngram} - aliases = %{ - "implies" => "implied_tags", - "implied_by" => "implied_by_tags", - "alias_of" => "aliased_tag" - } - - @tag_parser Parser.parser( - int_fields: int_fields, - literal_fields: literal_fields, - bool_fields: bool_fields, - ngram_fields: ngram_fields, - default_field: default_field, - aliases: aliases - ) + defp fields do + [ + int_fields: ~W(id images), + literal_fields: ~W(slug name name_in_namespace namespace implies alias_of implied_by aliases category analyzed_name), + bool_fields: ~W(aliased), + ngram_fields: ~W(description short_description), + default_field: {"analyzed_name", :ngram}, + aliases: %{ + "implies" => "implied_tags", + "implied_by" => "implied_by_tags", + "alias_of" => "aliased_tag" + } + ] + end def compile(query_string) do - query_string = query_string || "" - - Parser.parse(@tag_parser, query_string) + fields() + |> Parser.parser() + |> Parser.parse(query_string || "") end end