Skip to content
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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Account#triadic_closures #3079

Merged
merged 1 commit into from May 16, 2017
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 13 additions & 7 deletions app/models/account.rb
Expand Up @@ -259,24 +259,30 @@ def find_remote(username, domain)
nil
end

def triadic_closures(account, limit = 5)
def triadic_closures(account, limit: 5, offset: 0)
sql = <<-SQL.squish
WITH first_degree AS (
SELECT target_account_id
FROM follows
WHERE account_id = :account_id
)
SELECT target_account_id
FROM follows
WHERE account_id = :account_id
)
SELECT accounts.*
FROM follows
INNER JOIN accounts ON follows.target_account_id = accounts.id
WHERE account_id IN (SELECT * FROM first_degree) AND target_account_id NOT IN (SELECT * FROM first_degree) AND target_account_id <> :account_id
WHERE
account_id IN (SELECT * FROM first_degree)
AND target_account_id NOT IN (SELECT * FROM first_degree)
AND target_account_id NOT IN (:excluded_account_ids)
GROUP BY target_account_id, accounts.id
ORDER BY count(account_id) DESC
OFFSET :offset
LIMIT :limit
SQL

excluded_account_ids = account.excluded_from_timeline_account_ids + [account.id]

find_by_sql(
[sql, { account_id: account.id, limit: limit }]
[sql, { account_id: account.id, excluded_account_ids: excluded_account_ids, limit: limit, offset: offset }]
)
end

Expand Down
38 changes: 31 additions & 7 deletions spec/models/account_spec.rb
Expand Up @@ -261,19 +261,43 @@
end

describe '.triadic_closures' do
it 'finds accounts you dont follow which are followed by accounts you do follow' do
me = Fabricate(:account)
friend = Fabricate(:account)
friends_friend = Fabricate(:account)
subject { described_class.triadic_closures(me) }

let!(:me) { Fabricate(:account) }
let!(:friend) { Fabricate(:account) }
let!(:friends_friend) { Fabricate(:account) }
let!(:both_follow) { Fabricate(:account) }

before do
me.follow!(friend)
friend.follow!(friends_friend)

both_follow = Fabricate(:account)
me.follow!(both_follow)
friend.follow!(both_follow)
end

it 'finds accounts you dont follow which are followed by accounts you do follow' do
is_expected.to eq [friends_friend]
end

context 'when you block account' do
before do
me.block!(friends_friend)
end

it 'rejects blocked accounts' do
is_expected.to be_empty
end
end

results = Account.triadic_closures(me)
expect(results).to eq [friends_friend]
context 'when you mute account' do
before do
me.mute!(friends_friend)
end

it 'rejects muted accounts' do
is_expected.to be_empty
end
end
end

Expand Down