Delete duplicate records in different languages

Also logs a message when duplicates have different amounts, keeping the
first partial result and deleting the others.
This commit is contained in:
taitus
2025-09-11 09:33:01 +02:00
parent c9fb47aa3d
commit 24239c98e3
2 changed files with 147 additions and 25 deletions

View File

@@ -116,37 +116,58 @@ namespace :polls do
logger.info "Removing duplicate partial results in polls" logger.info "Removing duplicate partial results in polls"
Tenant.run_on_each do Tenant.run_on_each do
duplicate_ids = Poll::PartialResult.where(option_id: nil) Poll::Question.find_each do |question|
.select(:question_id, :booth_assignment_id, :date, :answer) manageable_titles = PollPartialResultOptionFinder.new(question).manageable_choices.keys
.group(:question_id, :booth_assignment_id, :date, :answer)
.having("count(*) > 1")
.pluck(:question_id, :booth_assignment_id, :date, :answer)
duplicate_ids.each do |question_id, booth_assignment_id, date, answer| question.question_options.each do |option|
partial_results = Poll::PartialResult.where( titles = option.translations.where(title: manageable_titles).select(:title).distinct
question_id: question_id,
groups = question.partial_results.where(option_id: nil, answer: titles)
.select(:booth_assignment_id, :date)
.group(:booth_assignment_id, :date)
.having("count(*) > 1")
.pluck(:booth_assignment_id, :date)
groups.each do |booth_assignment_id, date|
partial_results = question.partial_results.where(
option_id: nil,
booth_assignment_id: booth_assignment_id, booth_assignment_id: booth_assignment_id,
date: date, date: date,
answer: answer, answer: titles
option_id: nil
) )
tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default?
amounts_by_id = partial_results.pluck(:id, :amount).to_h
if amounts_by_id.values.uniq.size > 1
log_message = "Found duplicate partial results with different amounts " \
"for question_id #{question.id}, " \
"booth_assignment_id #{booth_assignment_id} " \
"and date #{date}. " \
"Keeping ID #{partial_results.first.id} " \
"with amount #{partial_results.first.amount}. " \
"Deleting partial results with these IDs and amounts: " \
"#{amounts_by_id.except(partial_results.first.id)}" + tenant_info.to_s
logger.info(log_message)
duplicate_records_logger.info(log_message)
end
partial_results.excluding(partial_results.first).each do |partial_result| partial_results.excluding(partial_results.first).each do |partial_result|
partial_result.delete partial_result.delete
tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default?
log_message = "Deleted duplicate record with ID #{partial_result.id} " \ log_message = "Deleted duplicate record with ID #{partial_result.id} " \
"from the #{Poll::PartialResult.table_name} table " \ "from the #{Poll::PartialResult.table_name} table " \
"with question_id #{question_id}, " \ "with question_id #{question.id}, " \
"booth_assignment_id #{booth_assignment_id}, " \ "booth_assignment_id #{booth_assignment_id} " \
"date #{date} " \ "and date #{date}" + tenant_info.to_s
"and answer #{answer}" + tenant_info.to_s
logger.info(log_message) logger.info(log_message)
duplicate_records_logger.info(log_message) duplicate_records_logger.info(log_message)
end end
end end
end end
end end
end
end
desc "populates the poll_partial_results option_id column" desc "populates the poll_partial_results option_id column"
task populate_partial_results_option_id: :remove_duplicate_partial_results do task populate_partial_results_option_id: :remove_duplicate_partial_results do

View File

@@ -258,6 +258,60 @@ describe "polls tasks" do
expect(Poll::PartialResult.all).to match_array [result, other_result, other_booth_result] expect(Poll::PartialResult.all).to match_array [result, other_result, other_booth_result]
end end
it "removes duplicate partial results in different languages" do
question = create(:poll_question_multiple, max_votes: 2)
create(:poll_question_option, question: question, title_en: "Yes", title_de: "Ja")
create(:poll_question_option, question: question, title_en: "No", title_de: "Nein")
create(:poll_question_option, question: question, title_en: "Maybe", title_de: "Vielleicht")
create(:poll_partial_result,
question: question,
booth_assignment_id: booth_assignment.id,
date: Date.current,
answer: "Yes",
option: nil)
create(:poll_partial_result,
question: question,
booth_assignment_id: booth_assignment.id,
date: Date.current,
answer: "Ja",
option: nil)
expect(Poll::PartialResult.count).to eq 2
Rake.application.invoke_task("polls:remove_duplicate_partial_results")
expect(Poll::PartialResult.count).to eq 1
end
it "does not remove duplicate partial results when many options are possible" do
question = create(:poll_question, title: "How do you pronounce it?")
create(:poll_question_option, question: question, title_en: "A", title_es: "EI")
create(:poll_question_option, question: question, title_en: "E", title_es: "I")
create(:poll_question_option, question: question, title_en: "I", title_es: "AI")
create(:poll_partial_result,
question: question,
booth_assignment_id: booth_assignment.id,
date: Date.current,
answer: "I",
option: nil)
create(:poll_partial_result,
question: question,
booth_assignment_id: booth_assignment.id,
date: Date.current,
answer: "AI",
option: nil)
expect(Poll::PartialResult.count).to eq 2
Rake.application.invoke_task("polls:remove_duplicate_partial_results")
expect(Poll::PartialResult.count).to eq 2
end
it "does not remove partial results with the same text and different options" do it "does not remove partial results with the same text and different options" do
question = create(:poll_question_multiple, :abcde, max_votes: 4) question = create(:poll_question_multiple, :abcde, max_votes: 4)
option_a = question.question_options.find_by(title: "Answer A") option_a = question.question_options.find_by(title: "Answer A")
@@ -305,6 +359,34 @@ describe "polls tasks" do
expect(Poll::PartialResult.count).to eq 1 expect(Poll::PartialResult.count).to eq 1
end end
end end
it "removes duplicates in different languages even when amounts differ" do
question = create(:poll_question_multiple, max_votes: 2)
create(:poll_question_option, question: question, title_en: "Yes", title_de: "Ja")
create(:poll_partial_result,
question: question,
booth_assignment_id: booth_assignment.id,
date: Date.current,
answer: "Yes",
option: nil,
amount: 3)
create(:poll_partial_result,
question: question,
booth_assignment_id: booth_assignment.id,
date: Date.current,
answer: "Ja",
option: nil,
amount: 5)
expect(Poll::PartialResult.count).to eq 2
Rake.application.invoke_task("polls:remove_duplicate_partial_results")
expect(Poll::PartialResult.count).to eq 1
end
end end
describe "polls:populate_partial_results_option_id" do describe "polls:populate_partial_results_option_id" do
@@ -381,6 +463,11 @@ describe "polls tasks" do
it "removes duplicate partial results before populating the option_id column" do it "removes duplicate partial results before populating the option_id column" do
question = create(:poll_question_multiple, :abc) question = create(:poll_question_multiple, :abc)
localized_question = create(:poll_question_multiple)
create(:poll_question_option, question: localized_question, title_en: "Yes", title_de: "Ja")
create(:poll_question_option, question: localized_question, title_en: "No", title_de: "Nein")
create(:poll_question_option, question: localized_question, title_en: "Maybe", title_de: "Vielleicht")
result_attributes = { result_attributes = {
question_id: question.id, question_id: question.id,
booth_assignment_id: booth_assignment.id, booth_assignment_id: booth_assignment.id,
@@ -391,14 +478,28 @@ describe "polls tasks" do
result = create(:poll_partial_result, result_attributes) result = create(:poll_partial_result, result_attributes)
insert(:poll_partial_result, result_attributes) insert(:poll_partial_result, result_attributes)
localized_result_attributes = {
question: localized_question,
booth_assignment_id: booth_assignment.id,
date: Date.current,
option: nil
}
localized_result = create(:poll_partial_result, localized_result_attributes.merge(answer: "Yes"))
create(:poll_partial_result, localized_result_attributes.merge(answer: "Ja"))
result.reload result.reload
localized_result.reload
expect(result.option_id).to be nil expect(result.option_id).to be nil
expect(localized_result.option_id).to be nil
Rake.application.invoke_task("polls:populate_partial_results_option_id") Rake.application.invoke_task("polls:populate_partial_results_option_id")
result.reload result.reload
localized_result.reload
expect(Poll::PartialResult.count).to eq 1 expect(Poll::PartialResult.count).to eq 2
expect(result.option_id).to eq question.question_options.find_by(title: "Answer A").id expect(result.option_id).to eq question.question_options.find_by(title: "Answer A").id
expect(localized_result.option_id).to eq localized_question.question_options.find_by(title: "Yes").id
end end
it "populates the option_id column on tenants" do it "populates the option_id column on tenants" do