FIX: on rebakes should not recreate quoted_posts records

Previously every rebake would remove and recreate records in this table
This caused created_at and updated_at to keep changing

Yes, I know the SQL is somewhat complex, but this makes quote extraction
more efficient cause we do everything in 2 round trips.

This also removes some concurrency protection we should no longer need
This commit is contained in:
Sam Saffron 2019-04-03 16:17:15 +11:00
parent 52c4711e80
commit b2dc65f953
2 changed files with 46 additions and 16 deletions

View File

@ -11,8 +11,6 @@ class QuotedPost < ActiveRecord::Base
uniq = {}
DB.exec("DELETE FROM quoted_posts WHERE post_id = :post_id", post_id: post.id)
doc.css("aside.quote[data-topic]").each do |a|
topic_id = a['data-topic'].to_i
post_number = a['data-post'].to_i
@ -22,21 +20,45 @@ class QuotedPost < ActiveRecord::Base
next if post.topic_id == topic_id && post.post_number == post_number
uniq[[topic_id, post_number]] = true
end
begin
# It would be so much nicer if we used post_id in quotes
DB.exec(<<~SQL, post_id: post.id, post_number: post_number, topic_id: topic_id)
INSERT INTO quoted_posts (post_id, quoted_post_id, created_at, updated_at)
SELECT :post_id, p.id, current_timestamp, current_timestamp
FROM posts p
LEFT JOIN quoted_posts q on q.post_id = :post_id AND q.quoted_post_id = p.id
WHERE post_number = :post_number AND
topic_id = :topic_id AND
q.id IS NULL
SQL
rescue ActiveRecord::RecordNotUnique, PG::UniqueViolation
# it's fine
end
if uniq.length == 0
DB.exec("DELETE FROM quoted_posts WHERE post_id = :post_id", post_id: post.id)
else
args = {
post_id: post.id,
topic_ids: uniq.keys.map(&:first),
post_numbers: uniq.keys.map(&:second)
}
DB.exec(<<~SQL, args)
INSERT INTO quoted_posts (post_id, quoted_post_id, created_at, updated_at)
SELECT :post_id, p.id, current_timestamp, current_timestamp
FROM posts p
JOIN (
SELECT
unnest(ARRAY[:topic_ids]) topic_id,
unnest(ARRAY[:post_numbers]) post_number
) X ON X.topic_id = p.topic_id AND X.post_number = p.post_number
LEFT JOIN quoted_posts q on q.post_id = :post_id AND q.quoted_post_id = p.id
WHERE q.id IS NULL
SQL
DB.exec(<<~SQL, args)
DELETE FROM quoted_posts
WHERE post_id = :post_id
AND id IN (
SELECT q1.id FROM quoted_posts q1
LEFT JOIN posts p1 ON p1.id = q1.quoted_post_id
LEFT JOIN (
SELECT
unnest(ARRAY[:topic_ids]) topic_id,
unnest(ARRAY[:post_numbers]) post_number
) X on X.topic_id = p1.topic_id AND X.post_number = p1.post_number
WHERE q1.post_id = :post_id AND X.topic_id IS NULL
)
SQL
end
# simplest place to add this code

View File

@ -70,11 +70,19 @@ describe QuotedPost do
HTML
QuotedPost.create!(post_id: post2.id, quoted_post_id: 999)
quote = QuotedPost.create!(post_id: post2.id, quoted_post_id: post1.id)
original_date = quote.created_at
freeze_time 1.hour.from_now
QuotedPost.extract_from(post2)
expect(QuotedPost.where(post_id: post2.id).count).to eq(1)
expect(QuotedPost.find_by(post_id: post2.id, quoted_post_id: post1.id)).not_to eq(nil)
quote.reload
expect(original_date).to eq_time(quote.created_at)
expect(post2.reply_quoted).to eq(false)
end
end