Search cleanup (#1333)
* Clean up SQL output in Tag and Account search methods * Add basic coverage for Tag.search_for * Add coverage for Account.search_for * Add coverage for Account.advanced_search_formain
parent
71706f21c2
commit
388ec0d5b6
|
@ -203,7 +203,7 @@ class Account < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def triadic_closures(account, limit = 5)
|
def triadic_closures(account, limit = 5)
|
||||||
sql = <<SQL
|
sql = <<-SQL.squish
|
||||||
WITH first_degree AS (
|
WITH first_degree AS (
|
||||||
SELECT target_account_id
|
SELECT target_account_id
|
||||||
FROM follows
|
FROM follows
|
||||||
|
@ -216,7 +216,7 @@ class Account < ApplicationRecord
|
||||||
GROUP BY target_account_id, accounts.id
|
GROUP BY target_account_id, accounts.id
|
||||||
ORDER BY count(account_id) DESC
|
ORDER BY count(account_id) DESC
|
||||||
LIMIT ?
|
LIMIT ?
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
Account.find_by_sql([sql, account.id, account.id, limit])
|
Account.find_by_sql([sql, account.id, account.id, limit])
|
||||||
end
|
end
|
||||||
|
@ -226,7 +226,7 @@ SQL
|
||||||
textsearch = '(setweight(to_tsvector(\'simple\', accounts.display_name), \'A\') || setweight(to_tsvector(\'simple\', accounts.username), \'B\') || setweight(to_tsvector(\'simple\', coalesce(accounts.domain, \'\')), \'C\'))'
|
textsearch = '(setweight(to_tsvector(\'simple\', accounts.display_name), \'A\') || setweight(to_tsvector(\'simple\', accounts.username), \'B\') || setweight(to_tsvector(\'simple\', coalesce(accounts.domain, \'\')), \'C\'))'
|
||||||
query = 'to_tsquery(\'simple\', \'\'\' \' || ' + terms + ' || \' \'\'\' || \':*\')'
|
query = 'to_tsquery(\'simple\', \'\'\' \' || ' + terms + ' || \' \'\'\' || \':*\')'
|
||||||
|
|
||||||
sql = <<SQL
|
sql = <<-SQL.squish
|
||||||
SELECT
|
SELECT
|
||||||
accounts.*,
|
accounts.*,
|
||||||
ts_rank_cd(#{textsearch}, #{query}, 32) AS rank
|
ts_rank_cd(#{textsearch}, #{query}, 32) AS rank
|
||||||
|
@ -234,7 +234,7 @@ SQL
|
||||||
WHERE #{query} @@ #{textsearch}
|
WHERE #{query} @@ #{textsearch}
|
||||||
ORDER BY rank DESC
|
ORDER BY rank DESC
|
||||||
LIMIT ?
|
LIMIT ?
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
Account.find_by_sql([sql, limit])
|
Account.find_by_sql([sql, limit])
|
||||||
end
|
end
|
||||||
|
@ -244,7 +244,7 @@ SQL
|
||||||
textsearch = '(setweight(to_tsvector(\'simple\', accounts.display_name), \'A\') || setweight(to_tsvector(\'simple\', accounts.username), \'B\') || setweight(to_tsvector(\'simple\', coalesce(accounts.domain, \'\')), \'C\'))'
|
textsearch = '(setweight(to_tsvector(\'simple\', accounts.display_name), \'A\') || setweight(to_tsvector(\'simple\', accounts.username), \'B\') || setweight(to_tsvector(\'simple\', coalesce(accounts.domain, \'\')), \'C\'))'
|
||||||
query = 'to_tsquery(\'simple\', \'\'\' \' || ' + terms + ' || \' \'\'\' || \':*\')'
|
query = 'to_tsquery(\'simple\', \'\'\' \' || ' + terms + ' || \' \'\'\' || \':*\')'
|
||||||
|
|
||||||
sql = <<SQL
|
sql = <<-SQL.squish
|
||||||
SELECT
|
SELECT
|
||||||
accounts.*,
|
accounts.*,
|
||||||
(count(f.id) + 1) * ts_rank_cd(#{textsearch}, #{query}, 32) AS rank
|
(count(f.id) + 1) * ts_rank_cd(#{textsearch}, #{query}, 32) AS rank
|
||||||
|
@ -254,7 +254,7 @@ SQL
|
||||||
GROUP BY accounts.id
|
GROUP BY accounts.id
|
||||||
ORDER BY rank DESC
|
ORDER BY rank DESC
|
||||||
LIMIT ?
|
LIMIT ?
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
Account.find_by_sql([sql, account.id, account.id, limit])
|
Account.find_by_sql([sql, account.id, account.id, limit])
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,7 +17,7 @@ class Tag < ApplicationRecord
|
||||||
textsearch = 'to_tsvector(\'simple\', tags.name)'
|
textsearch = 'to_tsvector(\'simple\', tags.name)'
|
||||||
query = 'to_tsquery(\'simple\', \'\'\' \' || ' + terms + ' || \' \'\'\' || \':*\')'
|
query = 'to_tsquery(\'simple\', \'\'\' \' || ' + terms + ' || \' \'\'\' || \':*\')'
|
||||||
|
|
||||||
sql = <<SQL
|
sql = <<-SQL.squish
|
||||||
SELECT
|
SELECT
|
||||||
tags.*,
|
tags.*,
|
||||||
ts_rank_cd(#{textsearch}, #{query}) AS rank
|
ts_rank_cd(#{textsearch}, #{query}) AS rank
|
||||||
|
@ -25,7 +25,7 @@ class Tag < ApplicationRecord
|
||||||
WHERE #{query} @@ #{textsearch}
|
WHERE #{query} @@ #{textsearch}
|
||||||
ORDER BY rank DESC
|
ORDER BY rank DESC
|
||||||
LIMIT ?
|
LIMIT ?
|
||||||
SQL
|
SQL
|
||||||
|
|
||||||
Tag.find_by_sql([sql, limit])
|
Tag.find_by_sql([sql, limit])
|
||||||
end
|
end
|
||||||
|
|
|
@ -170,6 +170,61 @@ RSpec.describe Account, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.search_for' do
|
||||||
|
before do
|
||||||
|
@match = Fabricate(
|
||||||
|
:account,
|
||||||
|
display_name: "Display Name",
|
||||||
|
username: "username",
|
||||||
|
domain: "example.com"
|
||||||
|
)
|
||||||
|
_missing = Fabricate(
|
||||||
|
:account,
|
||||||
|
display_name: "Missing",
|
||||||
|
username: "missing",
|
||||||
|
domain: "missing.com"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'finds accounts with matching display_name' do
|
||||||
|
results = Account.search_for("display")
|
||||||
|
expect(results).to eq [@match]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'finds accounts with matching username' do
|
||||||
|
results = Account.search_for("username")
|
||||||
|
expect(results).to eq [@match]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'finds accounts with matching domain' do
|
||||||
|
results = Account.search_for("example")
|
||||||
|
expect(results).to eq [@match]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'ranks multiple matches higher' do
|
||||||
|
account = Fabricate(
|
||||||
|
:account,
|
||||||
|
username: "username",
|
||||||
|
display_name: "username"
|
||||||
|
)
|
||||||
|
results = Account.search_for("username")
|
||||||
|
expect(results).to eq [account, @match]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.advanced_search_for' do
|
||||||
|
it 'ranks followed accounts higher' do
|
||||||
|
account = Fabricate(:account)
|
||||||
|
match = Fabricate(:account, username: "Matching")
|
||||||
|
followed_match = Fabricate(:account, username: "Matcher")
|
||||||
|
Fabricate(:follow, account: account, target_account: followed_match)
|
||||||
|
|
||||||
|
results = Account.advanced_search_for("match", account)
|
||||||
|
expect(results).to eq [followed_match, match]
|
||||||
|
expect(results.first.rank).to be > results.last.rank
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '.find_local' do
|
describe '.find_local' do
|
||||||
before do
|
before do
|
||||||
Fabricate(:account, username: 'Alice')
|
Fabricate(:account, username: 'Alice')
|
||||||
|
|
|
@ -12,4 +12,15 @@ RSpec.describe Tag, type: :model do
|
||||||
expect(subject.match('https://en.wikipedia.org/wiki/Ghostbusters_(song)#Lawsuit')).to be_nil
|
expect(subject.match('https://en.wikipedia.org/wiki/Ghostbusters_(song)#Lawsuit')).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.search_for' do
|
||||||
|
it 'finds tag records with matching names' do
|
||||||
|
tag = Fabricate(:tag, name: "match")
|
||||||
|
_miss_tag = Fabricate(:tag, name: "miss")
|
||||||
|
|
||||||
|
results = Tag.search_for("match")
|
||||||
|
|
||||||
|
expect(results).to eq [tag]
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue