Skip to content

Fix types of _id fields #525

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/philomena/comments/query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ defmodule Philomena.Comments.Query do
defp anonymous_fields do
[
int_fields: ~W(id),
numeric_fields: ~W(image_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},
Expand All @@ -77,7 +77,8 @@ defmodule Philomena.Comments.Query do
fields = user_fields()

Keyword.merge(fields,
literal_fields: ~W(image_id user_id author fingerprint),
numeric_fields: fields[:numeric_fields] ++ ~W(user_id),
literal_fields: ~W(author fingerprint),
ip_fields: ~W(ip),
bool_fields: ~W(anonymous deleted),
custom_fields: fields[:custom_fields] -- ~W(author user_id),
Expand Down
3 changes: 2 additions & 1 deletion lib/philomena/filters/query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ defmodule Philomena.Filters.Query do
defp anonymous_fields do
[
int_fields: ~W(id spoilered_count hidden_count),
numeric_fields: ~W(user_id),
date_fields: ~W(created_at),
ngram_fields: ~W(description),
literal_fields: ~W(name creator user_id),
literal_fields: ~W(name creator),
bool_fields: ~W(public system),
default_field: {"name", :term}
]
Expand Down
3 changes: 2 additions & 1 deletion lib/philomena/galleries/query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ defmodule Philomena.Galleries.Query do
defp fields do
[
int_fields: ~W(id image_count watcher_count),
literal_fields: ~W(title user image_ids watcher_ids),
numeric_fields: ~W(image_ids watcher_ids),
literal_fields: ~W(title user),
date_fields: ~W(created_at updated_at),
ngram_fields: ~W(description),
default_field: {"title", :term},
Expand Down
7 changes: 4 additions & 3 deletions lib/philomena/images/query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ defmodule Philomena.Images.Query do
defp anonymous_fields do
[
int_fields:
~W(id width height score upvotes downvotes faves uploader_id faved_by_id pixels size orig_size comment_count source_count tag_count) ++
~W(id width height score upvotes downvotes faves pixels size orig_size comment_count source_count tag_count) ++
tag_count_fields(),
numeric_fields: ~W(uploader_id faved_by_id duplicate_id),
float_fields: ~W(aspect_ratio wilson_score duration),
date_fields: ~W(created_at updated_at first_seen_at),
literal_fields:
Expand Down Expand Up @@ -118,8 +119,8 @@ defmodule Philomena.Images.Query do
fields = user_fields()

Keyword.merge(fields,
int_fields:
fields[:int_fields] ++
numeric_fields:
fields[:numeric_fields] ++
~W(upvoted_by_id downvoted_by_id true_uploader_id hidden_by_id deleted_by_user_id),
literal_fields:
fields[:literal_fields] ++
Expand Down
6 changes: 4 additions & 2 deletions lib/philomena/posts/query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ defmodule Philomena.Posts.Query do
defp anonymous_fields do
[
int_fields: ~W(id topic_position),
numeric_fields: ~W(forum_id topic_id),
date_fields: ~W(created_at updated_at),
literal_fields: ~W(forum forum_id topic_id),
literal_fields: ~W(forum),
ngram_fields: ~W(body subject),
custom_fields: ~W(author user_id),
default_field: {"body", :ngram},
Expand All @@ -76,7 +77,8 @@ defmodule Philomena.Posts.Query do
fields = user_fields()

Keyword.merge(fields,
literal_fields: fields[:literal_fields] ++ ~W(user_id author fingerprint),
numeric_fields: fields[:numeric_fields] ++ ~W(user_id),
literal_fields: fields[:literal_fields] ++ ~W(author fingerprint),
ip_fields: ~W(ip),
bool_fields: ~W(anonymous deleted),
custom_fields: fields[:custom_fields] -- ~W(author user_id),
Expand Down
6 changes: 3 additions & 3 deletions lib/philomena/reports/query.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ defmodule Philomena.Reports.Query do

defp fields do
[
int_fields: ~W(id image_id),
int_fields: ~W(id),
Copy link
Contributor

@MareStare MareStare May 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdashlw why not turn id into a numeric_field too?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it needs to support range querying

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it doesn't make sense to support range queries for relational IDs like image_id? IIRC it should cost nothing, right?

numeric_fields: ~W(user_id admin_id reportable_id image_id),
date_fields: ~W(created_at),
literal_fields:
~W(state user user_id admin admin_id reportable_type reportable_id fingerprint),
literal_fields: ~W(state user admin reportable_type fingerprint),
ip_fields: ~W(ip),
bool_fields: ~W(open),
ngram_fields: ~W(reason),
Expand Down
9 changes: 3 additions & 6 deletions lib/philomena_query/parse/float_parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ defmodule PhilomenaQuery.Parse.FloatParser do

import NimbleParsec

defp to_number(input), do: PhilomenaQuery.Parse.Helpers.to_number(input)
defp range(input), do: PhilomenaQuery.Parse.Helpers.range(input)

space =
choice([string(" "), string("\t"), string("\n"), string("\r"), string("\v"), string("\f")])
|> ignore()
Expand All @@ -18,21 +15,21 @@ defmodule PhilomenaQuery.Parse.FloatParser do
ascii_string([?0..?9], min: 1)
|> optional(ascii_char(~c".") |> ascii_string([?0..?9], min: 1))
|> reduce({List, :to_string, []})
|> reduce(:to_number)
|> reduce({PhilomenaQuery.Parse.Helpers, :to_number, []})

float =
optional(ascii_char(~c"-+"))
|> ascii_string([?0..?9], min: 1)
|> optional(ascii_char(~c".") |> ascii_string([?0..?9], min: 1))
|> reduce({List, :to_string, []})
|> reduce(:to_number)
|> reduce({PhilomenaQuery.Parse.Helpers, :to_number, []})

float_parser =
choice([
float
|> concat(fuzz)
|> concat(unsigned_float)
|> reduce(:range)
|> reduce({PhilomenaQuery.Parse.Helpers, :range, []})
|> unwrap_and_tag(:float_range),
float |> unwrap_and_tag(:float)
])
Expand Down
18 changes: 12 additions & 6 deletions lib/philomena_query/parse/helpers.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
defmodule PhilomenaQuery.Parse.Helpers do
@moduledoc false

@min_int32 -2_147_483_648
@max_int32 2_147_483_647

# Apparently, it's too hard for the standard library to to parse a number
# as a float if it doesn't contain a decimal point. WTF
def to_number(term) do
Expand All @@ -17,15 +20,18 @@ defmodule PhilomenaQuery.Parse.Helpers do
end

def to_int(term) do
{int, _} = :string.to_integer(term)
{int, []} = :string.to_integer(term)

if int in -2_147_483_648..2_147_483_647 do
int
else
0
end
clamp_to_int32(int)
end

def int_range([center, deviation]) do
[clamp_to_int32(center - deviation), clamp_to_int32(center + deviation)]
end

def clamp_to_int32(int) when is_integer(int),
do: min(max(int, @min_int32), @max_int32)

def range([center, deviation]) do
[center - deviation, center + deviation]
end
Expand Down
13 changes: 7 additions & 6 deletions lib/philomena_query/parse/int_parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ defmodule PhilomenaQuery.Parse.IntParser do

import NimbleParsec

defp to_int(input), do: PhilomenaQuery.Parse.Helpers.to_int(input)
defp range(input), do: PhilomenaQuery.Parse.Helpers.range(input)

space =
choice([string(" "), string("\t"), string("\n"), string("\r"), string("\v"), string("\f")])
|> ignore()
Expand All @@ -18,16 +15,20 @@ defmodule PhilomenaQuery.Parse.IntParser do
optional(ascii_char(~c"-+"))
|> ascii_string([?0..?9], min: 1)
|> reduce({List, :to_string, []})
|> reduce(:to_int)
|> reduce({PhilomenaQuery.Parse.Helpers, :to_int, []})

int_parser =
choice([
int |> concat(fuzz) |> integer(min: 1) |> reduce(:range) |> unwrap_and_tag(:int_range),
int
|> concat(fuzz)
|> integer(min: 1)
|> reduce({PhilomenaQuery.Parse.Helpers, :int_range, []})
|> unwrap_and_tag(:int_range),
int |> unwrap_and_tag(:int)
])
|> repeat(space)
|> eos()
|> label("an integer, like `3' or `-10'")
|> label("a signed integer, like `3' or `-10'")

defparsec(:parse, int_parser)
end
4 changes: 1 addition & 3 deletions lib/philomena_query/parse/lexer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ defmodule PhilomenaQuery.Parse.Lexer do

import NimbleParsec

defp to_number(input), do: PhilomenaQuery.Parse.Helpers.to_number(input)

space =
choice([string(" "), string("\t"), string("\n"), string("\r"), string("\v"), string("\f")])
|> ignore()
Expand All @@ -14,7 +12,7 @@ defmodule PhilomenaQuery.Parse.Lexer do
|> ascii_string([?0..?9], min: 1)
|> optional(ascii_char(~c".") |> ascii_string([?0..?9], min: 1))
|> reduce({List, :to_string, []})
|> reduce(:to_number)
|> reduce({PhilomenaQuery.Parse.Helpers, :to_number, []})

l_and =
times(space, min: 1)
Expand Down
4 changes: 1 addition & 3 deletions lib/philomena_query/parse/literal_parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ defmodule PhilomenaQuery.Parse.LiteralParser do
import NimbleParsec
@dialyzer [:no_match, :no_unused]

defp to_number(input), do: PhilomenaQuery.Parse.Helpers.to_number(input)

float =
ascii_string([?0..?9], min: 1)
|> optional(ascii_char(~c".") |> ascii_string([?0..?9], min: 1))
|> reduce({List, :to_string, []})
|> reduce(:to_number)
|> reduce({PhilomenaQuery.Parse.Helpers, :to_number, []})

edit_distance =
ignore(string("~"))
Expand Down
15 changes: 15 additions & 0 deletions lib/philomena_query/parse/numeric_parser.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule PhilomenaQuery.Parse.NumericParser do
@moduledoc false

import NimbleParsec

numeric_parser =
ascii_string([?0..?9], min: 1)
|> reduce({List, :to_string, []})
|> reduce({PhilomenaQuery.Parse.Helpers, :to_int, []})
|> unwrap_and_tag(:numeric)
|> eos()
|> label("a numeric value, like `3' or `10'")

defparsec(:parse, numeric_parser)
end
14 changes: 13 additions & 1 deletion lib/philomena_query/parse/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ defmodule PhilomenaQuery.Parse.Parser do
- Dates (absolute and relative, time points and ranges)
- Floats
- Integers
- Numerics
- IP Addresses
- Literal text
- Stemmed text
Expand All @@ -33,6 +34,7 @@ defmodule PhilomenaQuery.Parse.Parser do
DateParser,
FloatParser,
IntParser,
NumericParser,
IpParser,
Lexer,
LiteralParser,
Expand Down Expand Up @@ -90,6 +92,7 @@ defmodule PhilomenaQuery.Parse.Parser do
date_fields: [String.t()],
float_fields: [String.t()],
int_fields: [String.t()],
numeric_fields: [String.t()],
ip_fields: [String.t()],
literal_fields: [String.t()],
ngram_fields: [String.t()],
Expand All @@ -108,6 +111,7 @@ defmodule PhilomenaQuery.Parse.Parser do
date_fields: [],
float_fields: [],
int_fields: [],
numeric_fields: [],
ip_fields: [],
literal_fields: [],
ngram_fields: [],
Expand All @@ -131,7 +135,8 @@ defmodule PhilomenaQuery.Parse.Parser do
Available options:
- `bool_fields` - a list of field names parsed as booleans
- `float_fields` - a list of field names parsed as floats
- `int_fields` - a list of field names parsed as integers
- `int_fields` - a list of field names parsed as signed integers
- `numeric_fields` - a list of field names parsed as numeric values (unsigned integers without fuzzing or range queries)
- `ip_fields` - a list of field names parsed as IP CIDR masks
- `literal_fields` - wildcardable fields which are searched as the exact value
- `ngram_fields` - wildcardable fields which are searched as stemmed values
Expand Down Expand Up @@ -164,6 +169,7 @@ defmodule PhilomenaQuery.Parse.Parser do
Enum.map(parser.date_fields, fn f -> {f, DateParser} end) ++
Enum.map(parser.float_fields, fn f -> {f, FloatParser} end) ++
Enum.map(parser.int_fields, fn f -> {f, IntParser} end) ++
Enum.map(parser.numeric_fields, fn f -> {f, NumericParser} end) ++
Enum.map(parser.ip_fields, fn f -> {f, IpParser} end) ++
Enum.map(parser.literal_fields, fn f -> {f, LiteralParser} end) ++
Enum.map(parser.ngram_fields, fn f -> {f, NgramParser} end) ++
Expand Down Expand Up @@ -437,6 +443,12 @@ defmodule PhilomenaQuery.Parse.Parser do
defp field_type(_parser, [{IntParser, field_name}, range: _range, int_range: _value]),
do: {:error, "multiple ranges specified for " <> field_name}

defp field_type(parser, [{NumericParser, field_name}, range: :eq, numeric: value]),
do: {:ok, {%{term: %{field(parser, field_name) => value}}, []}}

defp field_type(_parser, [{NumericParser, field_name}, _range, _value]),
do: {:error, "range specified for " <> field_name}

defp field_type(parser, [{FloatParser, field_name}, range: :eq, float: value]),
do: {:ok, {%{term: %{field(parser, field_name) => value}}, []}}

Expand Down