+11
app/models/searchable.rb
+11
app/models/searchable.rb
···
24
}
25
26
scope :matching_terms, ->(terms) {
27
+
return self if terms.empty?
28
+
29
where(
30
(["(posts.text ~* ?)"] * (terms.length)).join(" AND "),
31
+
*(terms.map { |x| "\\y" + x.gsub(/\s+/, "\\s+") + "\\y" })
32
+
)
33
+
}
34
+
35
+
scope :excluding_terms, ->(terms) {
36
+
return self if terms.empty?
37
+
38
+
where(
39
+
(["(posts.text !~* ?)"] * (terms.length)).join(" AND "),
40
*(terms.map { |x| "\\y" + x.gsub(/\s+/, "\\s+") + "\\y" })
41
)
42
}
+20
-6
app/query_parser.rb
+20
-6
app/query_parser.rb
···
1
class QueryParser
2
-
attr_reader :terms
3
4
def initialize(query)
5
@terms = []
6
-
query = query.strip
7
8
-
while match = query.match(/".+?"/)
9
range = match.begin(0)...match.end(0)
10
-
phrase = query[range][1..-2].gsub(/[\W_]+/, ' ').strip
11
query[range] = ' '
12
-
@terms << phrase
13
end
14
15
-
@terms += query.gsub(/[\W_]+/, ' ').strip.split(/ +/)
16
end
17
end
···
1
class QueryParser
2
+
attr_reader :terms, :exclusions
3
4
def initialize(query)
5
@terms = []
6
+
@exclusions = []
7
+
8
+
query = query.clone
9
10
+
while match = query.match(/\-?".+?"/)
11
range = match.begin(0)...match.end(0)
12
+
phrase = query[range]
13
query[range] = ' '
14
+
15
+
negative = phrase.start_with?('-')
16
+
phrase = phrase.gsub(/^\-/, '').gsub(/^"|"$/, '').gsub(/[^\w\-]+/, ' ').strip
17
+
18
+
if negative
19
+
@exclusions << phrase
20
+
else
21
+
@terms << phrase
22
+
end
23
end
24
25
+
terms = query.gsub(/[^\w\-]+/, ' ').strip.split(/ +/)
26
+
negative, positive = terms.partition { |x| x.start_with?('-') }
27
+
28
+
@terms += positive
29
+
@exclusions += negative.map { |x| x[1..-1] }.reject(&:empty?)
30
end
31
end
+8
-3
app/server.rb
+8
-3
app/server.rb
···
55
return json_error('MissingParameter', 'Missing "collection" parameter')
56
end
57
58
-
terms = QueryParser.new(params[:query]).terms
59
60
collection = case params[:collection]
61
when 'likes' then user.likes
···
63
when 'quotes' then user.quotes
64
when 'reposts' then user.reposts
65
else return json_error('InvalidParameter', 'Invalid search collection')
66
end
67
68
items = collection
69
.joins(:post)
70
.includes(:post => :user)
71
-
.matching_terms(terms)
72
.reverse_chronologically
73
.after_cursor(params[:cursor])
74
.limit(PAGE_LIMIT)
···
80
items.map(&:post).map(&:at_uri)
81
end
82
83
-
json_response(terms: terms, posts: post_uris, cursor: items.last&.cursor)
84
end
85
86
get '/.well-known/did.json' do
···
55
return json_error('MissingParameter', 'Missing "collection" parameter')
56
end
57
58
+
query = QueryParser.new(params[:query])
59
60
collection = case params[:collection]
61
when 'likes' then user.likes
···
63
when 'quotes' then user.quotes
64
when 'reposts' then user.reposts
65
else return json_error('InvalidParameter', 'Invalid search collection')
66
+
end
67
+
68
+
if query.terms.empty?
69
+
return json_response(terms: [], posts: [], cursor: nil)
70
end
71
72
items = collection
73
.joins(:post)
74
.includes(:post => :user)
75
+
.matching_terms(query.terms)
76
+
.excluding_terms(query.exclusions)
77
.reverse_chronologically
78
.after_cursor(params[:cursor])
79
.limit(PAGE_LIMIT)
···
85
items.map(&:post).map(&:at_uri)
86
end
87
88
+
json_response(terms: query.terms, posts: post_uris, cursor: items.last&.cursor)
89
end
90
91
get '/.well-known/did.json' do