add macro api

This commit is contained in:
Liam P. White 2019-08-24 11:35:30 -04:00
parent 1ad4d1c574
commit c66fe0ca39
3 changed files with 399 additions and 253 deletions

View file

@ -0,0 +1,8 @@
defmodule Philomena.Images.Query do
use Philomena.Search.Lexer,
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(namespaced_tags.name faved_by orig_sha512_hash sha512_hash uploader source_url original_format),
ngram_fields: ~W(description)
end

View file

@ -13,4 +13,18 @@ defmodule Philomena.Search.Helpers do
int_val int_val
end end
end end
def full_choice(combinator \\ empty(), choices)
def full_choice(combinator, []) do
combinator |> eos()
end
def full_choice(combinator, [choice]) do
combinator |> concat(choice)
end
def full_choice(combinator, choices) do
choice(combinator, choices)
end
end end

View file

@ -1,4 +1,15 @@
defmodule Philomena.Search.Lexer do defmodule Philomena.Search.Lexer do
defmacro __using__(opts) do
literal_fields = Keyword.get(opts, :literal, [])
ngram_fields = Keyword.get(opts, :ngram, [])
bool_fields = Keyword.get(opts, :bool, [])
date_fields = Keyword.get(opts, :date, [])
float_fields = Keyword.get(opts, :float, [])
int_fields = Keyword.get(opts, :int, [])
ip_fields = Keyword.get(opts, :ip, [])
custom_fields = Keyword.get(opts, :custom, [])
quote location: :keep do
import NimbleParsec import NimbleParsec
import Philomena.Search.Helpers import Philomena.Search.Helpers
@ -228,23 +239,62 @@ defmodule Philomena.Search.Lexer do
relative_date relative_date
]) ])
eq = choice([string(":"), string(".eq:")]) |> unwrap_and_tag(:eq)
lt = string(".lt:") |> unwrap_and_tag(:lt)
lte = string(".lte:") |> unwrap_and_tag(:lte)
gt = string(".gt:") |> unwrap_and_tag(:gt)
gte = string(".gte:") |> unwrap_and_tag(:gte)
range_relation =
choice([
eq,
lt,
lte,
gt,
gte
])
boost = ignore(string("^")) |> unwrap_and_tag(number, :boost) boost = ignore(string("^")) |> unwrap_and_tag(number, :boost)
fuzz = ignore(string("~")) |> unwrap_and_tag(number, :fuzz) fuzz = ignore(string("~")) |> unwrap_and_tag(number, :fuzz)
quot = string("\"") quot = string("\"")
quoted_term = bool_value =
ignore(quot) full_choice(unquote(for f <- bool_fields, do: [string: f]))
|> choice([ |> concat(eq)
ignore(string("\\")) |> string("\""), |> concat(bool)
ignore(string("\\")) |> string("\\"),
string("\\") |> utf8_char([]), date_value =
utf8_char(not: ?") full_choice(unquote(for f <- date_fields, do: [string: f]))
|> concat(range_relation)
|> concat(date)
float_value =
full_choice(unquote(for f <- float_fields, do: [string: f]))
|> concat(range_relation)
|> concat(number)
int_value =
full_choice(unquote(for f <- int_fields, do: [string: f]))
|> concat(range_relation)
|> concat(int)
ip_value =
full_choice(unquote(for f <- ip_fields, do: [string: f]))
|> concat(eq)
|> concat(ip_address)
numeric =
choice([
bool_value,
date_value,
float_value,
int_value,
ip_value
]) ])
|> times(min: 1)
|> ignore(quot) quoted_numeric =
|> reduce({List, :to_string, []}) ignore(quot) |> concat(numeric) |> ignore(quot)
|> unwrap_and_tag(:term)
stop_words = stop_words =
choice([ choice([
@ -259,20 +309,93 @@ defmodule Philomena.Search.Lexer do
]) ])
defcombinatorp( defcombinatorp(
:simple_term, :text,
lookahead_not(stop_words) lookahead_not(stop_words)
|> choice([ |> choice([
string("\\") |> utf8_char([]), string("\\") |> utf8_char([]),
string("(") |> parsec(:simple_term) |> string(")"), string("(") |> parsec(:text) |> string(")"),
utf8_char([]) utf8_char([])
]) ])
|> times(min: 1) |> times(min: 1)
|> reduce({List, :to_string, []})
|> unwrap_and_tag(:text)
) )
unquoted_term = text = parsec(:text)
parsec(:simple_term)
quoted_text =
choice([
ignore(string("\\")) |> string("\""),
ignore(string("\\")) |> string("\\"),
string("\\") |> utf8_char([]),
utf8_char(not: ?")
])
|> times(min: 1)
|> reduce({List, :to_string, []}) |> reduce({List, :to_string, []})
|> unwrap_and_tag(:term) |> unwrap_and_tag(:text)
literal =
full_choice(unquote(for f <- literal_fields, do: [string: f]))
|> ignore(eq)
|> concat(text)
|> tag(:literal)
ngram =
full_choice(unquote(for f <- ngram_fields, do: [string: f]))
|> ignore(eq)
|> concat(text)
|> tag(:ngram)
custom =
full_choice(unquote(for f <- custom_fields, do: [string: f]))
|> ignore(string(":"))
|> concat(text)
quoted_literal =
ignore(quot)
|> full_choice(unquote(for f <- literal_fields, do: [string: f]))
|> ignore(eq)
|> concat(quoted_text)
|> ignore(quot)
|> tag(:literal)
quoted_ngram =
ignore(quot)
|> full_choice(unquote(for f <- ngram_fields, do: [string: f]))
|> ignore(eq)
|> concat(quoted_text)
|> ignore(quot)
|> tag(:ngram)
quoted_custom =
ignore(quot)
|> full_choice(unquote(for f <- custom_fields, do: [string: f]))
|> ignore(string(":"))
|> concat(quoted_text)
|> ignore(quot)
|> tag(:custom)
default =
text
|> tag(:default)
quoted_default =
quoted_text
|> tag(:default)
term =
choice([
quoted_numeric,
quoted_literal,
quoted_ngram,
quoted_custom,
quoted_default,
numeric,
literal,
ngram,
custom,
default
])
outer = outer =
choice([ choice([
@ -284,8 +407,7 @@ defmodule Philomena.Search.Lexer do
boost, boost,
fuzz, fuzz,
space, space,
quoted_term, term
unquoted_term
]) ])
search = search =
@ -293,4 +415,6 @@ defmodule Philomena.Search.Lexer do
|> eos() |> eos()
defparsec(:search, search) defparsec(:search, search)
end
end
end end