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_for
This commit is contained in:
		
							parent
							
								
									71706f21c2
								
							
						
					
					
						commit
						388ec0d5b6
					
				
					 4 changed files with 74 additions and 8 deletions
				
			
		| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 a new issue