From 3179f28ef3affb63d021001d4ad0d5450c1a1498 Mon Sep 17 00:00:00 2001 From: zhouyu Date: Wed, 1 Oct 2025 09:28:15 -0700 Subject: [PATCH 01/12] Add migrations for AP-427 --- db/migrate/20250930215317_add_two_facets.rb | 12 +++++ .../20250930220140_add_three_ordered_terms.rb | 29 +++++++++++ ...0250930220504_update_term_item_relation.rb | 52 +++++++++++++++++++ ...930230620_update_fix_term_item_relation.rb | 46 ++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 db/migrate/20250930215317_add_two_facets.rb create mode 100644 db/migrate/20250930220140_add_three_ordered_terms.rb create mode 100644 db/migrate/20250930220504_update_term_item_relation.rb create mode 100644 db/migrate/20250930230620_update_fix_term_item_relation.rb diff --git a/db/migrate/20250930215317_add_two_facets.rb b/db/migrate/20250930215317_add_two_facets.rb new file mode 100644 index 0000000..d3a16a8 --- /dev/null +++ b/db/migrate/20250930215317_add_two_facets.rb @@ -0,0 +1,12 @@ +class AddTwoFacets < ActiveRecord::Migration[7.0] + def up + facet = Facet.find_by!(name: "Medium") + Term.create!(facet: facet, value: "Digital") + Term.create!(facet: facet, value: "Drawing") + end + + def down + facet = Facet.find_by(name: "Medium") + Term.where(facet: facet, value: ["Digital", "Drawing"]).delete_all + end +end diff --git a/db/migrate/20250930220140_add_three_ordered_terms.rb b/db/migrate/20250930220140_add_three_ordered_terms.rb new file mode 100644 index 0000000..7d033c7 --- /dev/null +++ b/db/migrate/20250930220140_add_three_ordered_terms.rb @@ -0,0 +1,29 @@ +class AddThreeOrderedTerms < ActiveRecord::Migration[7.0] + def up + facet = Facet.find_by!(name: "Decade") + + # Add and remove terms from facet "Decade", and reorder them. + # The term "After 1999" is no longer needed and will be removed + # when all items_terms have been updated + term = Term.find_by!(facet: facet, value: "After 1999") + term.update!(ord: 15) + term = Term.find_by!(facet: facet, value: "No Date") + term.update!(ord: 14) + + Term.create!(facet: facet, value: "2000-2009", ord: 11) + Term.create!(facet: facet, value: "2010-2019", ord: 12) + Term.create!(facet: facet, value: "After 2020",ord: 13) + end + + def down + facet = Facet.find_by(name: "Decade") + return unless facet + + Term.where(facet: facet, value: ["2000-2009", "2010-2019", "After 2020"]).delete_all + term = Term.find_by!(facet: facet, value: "After 1999") + term.update!(ord: 11) + term = Term.find_by!(facet: facet, value: "No Date") + term.update!(ord: 12) + end +end + diff --git a/db/migrate/20250930220504_update_term_item_relation.rb b/db/migrate/20250930220504_update_term_item_relation.rb new file mode 100644 index 0000000..2514fff --- /dev/null +++ b/db/migrate/20250930220504_update_term_item_relation.rb @@ -0,0 +1,52 @@ +class UpdateTermItemRelation < ActiveRecord::Migration[7.0] + def up + facet = Facet.find_by!(name: 'Decade') + old_term = Term.find_by!(facet: facet, value: 'After 1999') + + new_terms = { + (2000..2009) => Term.find_by!(facet: facet, value: '2000-2009'), + (2010..2019) => Term.find_by!(facet: facet, value: '2010-2019'), + (2020..) => Term.find_by!(facet: facet, value: 'After 2020') + } + + old_term.items.find_each do |item| + year = integer_year(item.date) + next unless year + + target_term = new_terms.find { |range, _| range.cover?(year) }&.last + next unless target_term + + update_item(item, old_term, target_term) + end + end + + def down + facet = Facet.find_by!(name: 'Decade') + target_term = Term.find_by!(facet: facet, value: 'After 1999') + roll_back(facet, target_term, '2000-2009') + roll_back(facet, target_term, '2010-2019') + roll_back(facet, target_term, 'After 2020') + end + + private + + def integer_year(val) + Integer(val) + rescue ArgumentError, TypeError + nil + end + + def update_item(item, origin_term, target_term) + return unless target_term & item & target_term + + item.terms.delete(origin_term) + item.terms << target_term unless item.terms.include?(target_term) + end + + def roll_back(facet, target_term, origin_term_value) + origin_term = Term.find_by!(facet: facet, value: origin_term_value) + origin_term.items.find_each do |item| + update_item(item, origin_term, target_term) + end + end +end diff --git a/db/migrate/20250930230620_update_fix_term_item_relation.rb b/db/migrate/20250930230620_update_fix_term_item_relation.rb new file mode 100644 index 0000000..6c5e0e2 --- /dev/null +++ b/db/migrate/20250930230620_update_fix_term_item_relation.rb @@ -0,0 +1,46 @@ +class UpdateFixTermItemRelation < ActiveRecord::Migration[7.0] + def up + execute <<~SQL.squish + old_id = select_value("SELECT id FROM terms WHERE value = 'After 1999'") + new_id = select_value("SELECT id FROM terms WHERE value = 'After 2020'") + return unless old_id && new_id + + WITH target AS ( + SELECT it.term_id, it.item_id + FROM items i + JOIN items_terms it ON i.id = it.item_id + JOIN terms t ON it.term_id = t.id + WHERE t.id = #{old_id} + AND i.date = '[2020]' + ) + UPDATE items_terms it + SET term_id = #{new_id} + FROM target + WHERE it.item_id = target.item_id + AND it.term_id = target.term_id; + SQL + end + + def up + new_id = select_value("SELECT id FROM terms WHERE value = 'After 1999'") + old_id = select_value("SELECT id FROM terms WHERE value = 'After 2020'") + return unless old_id && new_id + + execute <<~SQL.squish + WITH target AS ( + SELECT it.term_id, it.item_id + FROM items i + JOIN items_terms it ON i.id = it.item_id + JOIN terms t ON it.term_id = t.id + WHERE t.id = #{old_id} + AND i.date = '[2020]' + ) + UPDATE items_terms it + SET term_id = #{new_id} + FROM target + WHERE it.item_id = target.item_id + AND it.term_id = target.term_id; + SQL + end + +end From a0ca4ac4530b0278dc58a1f8a81dcd54cd9da325 Mon Sep 17 00:00:00 2001 From: zhouyu Date: Wed, 1 Oct 2025 09:42:26 -0700 Subject: [PATCH 02/12] Change variable names --- ...930230620_update_fix_term_item_relation.rb | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/db/migrate/20250930230620_update_fix_term_item_relation.rb b/db/migrate/20250930230620_update_fix_term_item_relation.rb index 6c5e0e2..557e628 100644 --- a/db/migrate/20250930230620_update_fix_term_item_relation.rb +++ b/db/migrate/20250930230620_update_fix_term_item_relation.rb @@ -1,30 +1,30 @@ class UpdateFixTermItemRelation < ActiveRecord::Migration[7.0] def up + after_1999_id = select_value("SELECT id FROM terms WHERE value = 'After 1999'") + after_2000_id = select_value("SELECT id FROM terms WHERE value = 'After 2020'") + return unless after_1999_id && after_2000_id + execute <<~SQL.squish - old_id = select_value("SELECT id FROM terms WHERE value = 'After 1999'") - new_id = select_value("SELECT id FROM terms WHERE value = 'After 2020'") - return unless old_id && new_id - WITH target AS ( SELECT it.term_id, it.item_id FROM items i JOIN items_terms it ON i.id = it.item_id JOIN terms t ON it.term_id = t.id - WHERE t.id = #{old_id} + WHERE t.id = #{after_1999_id} AND i.date = '[2020]' ) UPDATE items_terms it - SET term_id = #{new_id} + SET term_id = #{after_2000_id} FROM target WHERE it.item_id = target.item_id AND it.term_id = target.term_id; SQL end - def up - new_id = select_value("SELECT id FROM terms WHERE value = 'After 1999'") - old_id = select_value("SELECT id FROM terms WHERE value = 'After 2020'") - return unless old_id && new_id + def down + after_1999_id = select_value("SELECT id FROM terms WHERE value = 'After 1999'") + after_2000_id = select_value("SELECT id FROM terms WHERE value = 'After 2020'") + return unless after_1999_id && after_2000_id execute <<~SQL.squish WITH target AS ( @@ -32,11 +32,11 @@ def up FROM items i JOIN items_terms it ON i.id = it.item_id JOIN terms t ON it.term_id = t.id - WHERE t.id = #{old_id} + WHERE t.id = #{after_2000_id} AND i.date = '[2020]' ) UPDATE items_terms it - SET term_id = #{new_id} + SET term_id = #{after_1999_id} FROM target WHERE it.item_id = target.item_id AND it.term_id = target.term_id; From a7a5a89bb7d16de8d4fc7b3ccd0828be88a8fea9 Mon Sep 17 00:00:00 2001 From: zhouyu Date: Wed, 1 Oct 2025 09:49:13 -0700 Subject: [PATCH 03/12] Update variable name --- .../20250930230620_update_fix_term_item_relation.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/db/migrate/20250930230620_update_fix_term_item_relation.rb b/db/migrate/20250930230620_update_fix_term_item_relation.rb index 557e628..63481d4 100644 --- a/db/migrate/20250930230620_update_fix_term_item_relation.rb +++ b/db/migrate/20250930230620_update_fix_term_item_relation.rb @@ -1,8 +1,8 @@ class UpdateFixTermItemRelation < ActiveRecord::Migration[7.0] def up after_1999_id = select_value("SELECT id FROM terms WHERE value = 'After 1999'") - after_2000_id = select_value("SELECT id FROM terms WHERE value = 'After 2020'") - return unless after_1999_id && after_2000_id + after_2020_id = select_value("SELECT id FROM terms WHERE value = 'After 2020'") + return unless after_1999_id && after_2020_id execute <<~SQL.squish WITH target AS ( @@ -14,7 +14,7 @@ def up AND i.date = '[2020]' ) UPDATE items_terms it - SET term_id = #{after_2000_id} + SET term_id = #{after_2020_id} FROM target WHERE it.item_id = target.item_id AND it.term_id = target.term_id; @@ -23,8 +23,8 @@ def up def down after_1999_id = select_value("SELECT id FROM terms WHERE value = 'After 1999'") - after_2000_id = select_value("SELECT id FROM terms WHERE value = 'After 2020'") - return unless after_1999_id && after_2000_id + after_2020_id = select_value("SELECT id FROM terms WHERE value = 'After 2020'") + return unless after_1999_id && after_2020_id execute <<~SQL.squish WITH target AS ( @@ -32,7 +32,7 @@ def down FROM items i JOIN items_terms it ON i.id = it.item_id JOIN terms t ON it.term_id = t.id - WHERE t.id = #{after_2000_id} + WHERE t.id = #{after_2020_id} AND i.date = '[2020]' ) UPDATE items_terms it From 72d96d1d2a4eb0d654880b5a87d36b26d6e32a04 Mon Sep 17 00:00:00 2001 From: zhouyu Date: Wed, 1 Oct 2025 13:34:06 -0700 Subject: [PATCH 04/12] Add comments and update some functions --- ...0250930220504_update_term_item_relation.rb | 55 +++++++++++++------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/db/migrate/20250930220504_update_term_item_relation.rb b/db/migrate/20250930220504_update_term_item_relation.rb index 2514fff..f610a9c 100644 --- a/db/migrate/20250930220504_update_term_item_relation.rb +++ b/db/migrate/20250930220504_update_term_item_relation.rb @@ -1,7 +1,7 @@ class UpdateTermItemRelation < ActiveRecord::Migration[7.0] def up facet = Facet.find_by!(name: 'Decade') - old_term = Term.find_by!(facet: facet, value: 'After 1999') + t_after_2019 = Term.find_by!(facet: facet, value: 'After 1999') new_terms = { (2000..2009) => Term.find_by!(facet: facet, value: '2000-2009'), @@ -9,44 +9,63 @@ def up (2020..) => Term.find_by!(facet: facet, value: 'After 2020') } - old_term.items.find_each do |item| + invalid_items = [] + + t_after_2019.items.find_each do |item| year = integer_year(item.date) - next unless year + unless year + invalid_items << { id: item.id, date: item.date } + next + end target_term = new_terms.find { |range, _| range.cover?(year) }&.last next unless target_term - update_item(item, old_term, target_term) - end + re_assign_term_to_item(item, t_after_2019, target_term) + end + + if invalid_items.any? + Rails.logger.warn("Skipped #{invalid_items.size} items due to invalid or missing dates. Example: #{invalid_items.first(10).map { |i| "ID #{i[:id]}: '#{i[:date]}'" }.join(', ')}") + end end def down facet = Facet.find_by!(name: 'Decade') target_term = Term.find_by!(facet: facet, value: 'After 1999') - roll_back(facet, target_term, '2000-2009') - roll_back(facet, target_term, '2010-2019') - roll_back(facet, target_term, 'After 2020') + move_term_back_to_item(facet, target_term, '2000-2009') + move_term_back_to_item(facet, target_term, '2010-2019') + move_term_back_to_item(facet, target_term, 'After 2020') end private - + def integer_year(val) - Integer(val) - rescue ArgumentError, TypeError - nil - end + return nil if val.nil? - def update_item(item, origin_term, target_term) - return unless target_term & item & target_term + # Try direct integer conversion + begin + return Integer(val) + rescue ArgumentError, TypeError + # Try to extract year from common date formats (e.g., "YYYY-MM-DD", "YYYY/MM/DD") + if val.is_a?(String) + if val =~ /\A(\d{4})[-\/]/ + return $1.to_i + end + end + end + end - item.terms.delete(origin_term) + # Reassigns an item from the origin term to the target term, and removes the origin term from the item. + def re_assign_term_to_item(item, origin_term, target_term) item.terms << target_term unless item.terms.include?(target_term) + item.terms.delete(origin_term) end - def roll_back(facet, target_term, origin_term_value) + # Rolls back term assignment from origin_term_value to target_term for all items. + def move_term_back_to_item(facet, target_term, origin_term_value) origin_term = Term.find_by!(facet: facet, value: origin_term_value) origin_term.items.find_each do |item| - update_item(item, origin_term, target_term) + re_assign_term_to_item(item, origin_term, target_term) end end end From 926632d44f16bf61a23090e8d3bedc881c63a58d Mon Sep 17 00:00:00 2001 From: zhouyu Date: Wed, 1 Oct 2025 14:26:46 -0700 Subject: [PATCH 05/12] Fix the special items --- ...930230620_update_fix_term_item_relation.rb | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/db/migrate/20250930230620_update_fix_term_item_relation.rb b/db/migrate/20250930230620_update_fix_term_item_relation.rb index 63481d4..609dfb2 100644 --- a/db/migrate/20250930230620_update_fix_term_item_relation.rb +++ b/db/migrate/20250930230620_update_fix_term_item_relation.rb @@ -1,46 +1,47 @@ +# Update terms of the three items whose value is nil or not in date or year format class UpdateFixTermItemRelation < ActiveRecord::Migration[7.0] def up - after_1999_id = select_value("SELECT id FROM terms WHERE value = 'After 1999'") - after_2020_id = select_value("SELECT id FROM terms WHERE value = 'After 2020'") - return unless after_1999_id && after_2020_id - - execute <<~SQL.squish - WITH target AS ( - SELECT it.term_id, it.item_id - FROM items i - JOIN items_terms it ON i.id = it.item_id - JOIN terms t ON it.term_id = t.id - WHERE t.id = #{after_1999_id} - AND i.date = '[2020]' - ) - UPDATE items_terms it - SET term_id = #{after_2020_id} - FROM target - WHERE it.item_id = target.item_id - AND it.term_id = target.term_id; - SQL + facet = Facet.find_by!(name: 'Decade') + t_after_1999 = Term.find_by!(facet: facet, value: 'After 1999') + t2000_2009 = Term.find_by!(facet: facet, value: '2000-2009') + t2020_plus = Term.find_by!(facet: facet, value: 'After 2020') + + # Items with nil date + insert_and_delete(t_after_1999.id, t2000_2009.id, "i.date is null AND i.title in ('Loading a Cannon', 'Dense Populations')") + # Items with date = '[2020]' + insert_and_delete(t_after_1999.id, t2020_plus.id, "date = '[2020]'") end def down - after_1999_id = select_value("SELECT id FROM terms WHERE value = 'After 1999'") - after_2020_id = select_value("SELECT id FROM terms WHERE value = 'After 2020'") - return unless after_1999_id && after_2020_id + facet = Facet.find_by!(name: 'Decade') + t_after_1999 = Term.find_by!(facet: facet, value: 'After 1999') + t2000_2009 = Term.find_by!(facet: facet, value: '2000-2009') + t2020_plus = Term.find_by!(facet: facet, value: 'After 2020') + + # revert items with nil date + insert_and_delete(t2000_2009.id,t_after_1999.id, "i.date is null AND i.title in ('Loading a Cannon', 'Dense Populations')") + # revert items with date = '[2020]' + insert_and_delete(t2020_plus.id, t_after_1999.id, "date = '[2020]'") + end + + private + + def insert_and_delete(old_term_id, new_term_id, condition_sql) execute <<~SQL.squish WITH target AS ( - SELECT it.term_id, it.item_id + SELECT it.term_id, it.item_id, i.title FROM items i JOIN items_terms it ON i.id = it.item_id JOIN terms t ON it.term_id = t.id - WHERE t.id = #{after_2020_id} - AND i.date = '[2020]' + WHERE t.id = #{old_term_id} + AND #{condition_sql} ) UPDATE items_terms it - SET term_id = #{after_1999_id} + SET term_id = #{new_term_id} FROM target WHERE it.item_id = target.item_id AND it.term_id = target.term_id; SQL end - end From 173b7657a092ee5a7e8aad91ec778464c079b8b8 Mon Sep 17 00:00:00 2001 From: zhouyu Date: Wed, 1 Oct 2025 15:11:29 -0700 Subject: [PATCH 06/12] Push the schema.rb with latest migration timestamp --- db/schema.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/schema.rb b/db/schema.rb index 7e064a9..70b1c8f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_12_08_181611) do +ActiveRecord::Schema[7.0].define(version: 2025_09_30_230620) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" From a010831c8a646aa035ca9b5dc9ed4a3adacbae10 Mon Sep 17 00:00:00 2001 From: zhouyu Date: Wed, 1 Oct 2025 16:11:14 -0700 Subject: [PATCH 07/12] Drop term After 1999 --- db/migrate/20251001223022_drop_term_after1999.rb | 11 +++++++++++ db/schema.rb | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20251001223022_drop_term_after1999.rb diff --git a/db/migrate/20251001223022_drop_term_after1999.rb b/db/migrate/20251001223022_drop_term_after1999.rb new file mode 100644 index 0000000..1a32ae9 --- /dev/null +++ b/db/migrate/20251001223022_drop_term_after1999.rb @@ -0,0 +1,11 @@ +class DropTermAfter1999 < ActiveRecord::Migration[7.0] + def up + facet = Facet.find_by!(name: 'Decade') + exec_delete("DELETE FROM terms WHERE facet_id = #{facet.id} and value = 'After 1999' and ord = 15") + end + + def down + facet = Facet.find_by!(name: 'Decade') + Term.create!(facet: facet, value: "After 1999", ord: 15) + end +end diff --git a/db/schema.rb b/db/schema.rb index 70b1c8f..8993802 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2025_09_30_230620) do +ActiveRecord::Schema[7.0].define(version: 2025_10_01_223022) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" From da4bc37016795035f8aebe48621eb8ae65a66b86 Mon Sep 17 00:00:00 2001 From: zhouyu Date: Thu, 2 Oct 2025 10:33:29 -0700 Subject: [PATCH 08/12] Update some methods --- ...two_facets.rb => 20250930215317_add_two_terms.rb} | 4 ++-- db/migrate/20250930220140_add_three_ordered_terms.rb | 4 +--- .../20250930220504_update_term_item_relation.rb | 9 +++++---- .../20250930230620_update_fix_term_item_relation.rb | 12 ++++++------ 4 files changed, 14 insertions(+), 15 deletions(-) rename db/migrate/{20250930215317_add_two_facets.rb => 20250930215317_add_two_terms.rb} (73%) diff --git a/db/migrate/20250930215317_add_two_facets.rb b/db/migrate/20250930215317_add_two_terms.rb similarity index 73% rename from db/migrate/20250930215317_add_two_facets.rb rename to db/migrate/20250930215317_add_two_terms.rb index d3a16a8..39395ba 100644 --- a/db/migrate/20250930215317_add_two_facets.rb +++ b/db/migrate/20250930215317_add_two_terms.rb @@ -1,4 +1,4 @@ -class AddTwoFacets < ActiveRecord::Migration[7.0] +class AddTwoTerms < ActiveRecord::Migration[7.0] def up facet = Facet.find_by!(name: "Medium") Term.create!(facet: facet, value: "Digital") @@ -6,7 +6,7 @@ def up end def down - facet = Facet.find_by(name: "Medium") + facet = Facet.find_by!(name: "Medium") Term.where(facet: facet, value: ["Digital", "Drawing"]).delete_all end end diff --git a/db/migrate/20250930220140_add_three_ordered_terms.rb b/db/migrate/20250930220140_add_three_ordered_terms.rb index 7d033c7..abdad5f 100644 --- a/db/migrate/20250930220140_add_three_ordered_terms.rb +++ b/db/migrate/20250930220140_add_three_ordered_terms.rb @@ -16,9 +16,7 @@ def up end def down - facet = Facet.find_by(name: "Decade") - return unless facet - + facet = Facet.find_by!(name: "Decade") Term.where(facet: facet, value: ["2000-2009", "2010-2019", "After 2020"]).delete_all term = Term.find_by!(facet: facet, value: "After 1999") term.update!(ord: 11) diff --git a/db/migrate/20250930220504_update_term_item_relation.rb b/db/migrate/20250930220504_update_term_item_relation.rb index f610a9c..7c5e92b 100644 --- a/db/migrate/20250930220504_update_term_item_relation.rb +++ b/db/migrate/20250930220504_update_term_item_relation.rb @@ -32,9 +32,9 @@ def up def down facet = Facet.find_by!(name: 'Decade') target_term = Term.find_by!(facet: facet, value: 'After 1999') - move_term_back_to_item(facet, target_term, '2000-2009') - move_term_back_to_item(facet, target_term, '2010-2019') - move_term_back_to_item(facet, target_term, 'After 2020') + move_term_back_to_item(facet, '2000-2009', target_term) + move_term_back_to_item(facet, '2010-2019', target_term) + move_term_back_to_item(facet, 'After 2020', target_term) end private @@ -52,6 +52,7 @@ def integer_year(val) return $1.to_i end end + return nil end end @@ -62,7 +63,7 @@ def re_assign_term_to_item(item, origin_term, target_term) end # Rolls back term assignment from origin_term_value to target_term for all items. - def move_term_back_to_item(facet, target_term, origin_term_value) + def move_term_back_to_item(facet, origin_term_value, target_term) origin_term = Term.find_by!(facet: facet, value: origin_term_value) origin_term.items.find_each do |item| re_assign_term_to_item(item, origin_term, target_term) diff --git a/db/migrate/20250930230620_update_fix_term_item_relation.rb b/db/migrate/20250930230620_update_fix_term_item_relation.rb index 609dfb2..54ea031 100644 --- a/db/migrate/20250930230620_update_fix_term_item_relation.rb +++ b/db/migrate/20250930230620_update_fix_term_item_relation.rb @@ -7,9 +7,9 @@ def up t2020_plus = Term.find_by!(facet: facet, value: 'After 2020') # Items with nil date - insert_and_delete(t_after_1999.id, t2000_2009.id, "i.date is null AND i.title in ('Loading a Cannon', 'Dense Populations')") + update_item_term(t_after_1999.id, t2000_2009.id, "i.date is null AND i.title in ('Loading a Cannon', 'Dense Populations')") # Items with date = '[2020]' - insert_and_delete(t_after_1999.id, t2020_plus.id, "date = '[2020]'") + update_item_term(t_after_1999.id, t2020_plus.id, "date = '[2020]'") end def down @@ -19,18 +19,18 @@ def down t2020_plus = Term.find_by!(facet: facet, value: 'After 2020') # revert items with nil date - insert_and_delete(t2000_2009.id,t_after_1999.id, "i.date is null AND i.title in ('Loading a Cannon', 'Dense Populations')") + update_item_term(t2000_2009.id,t_after_1999.id, "i.date is null AND i.title in ('Loading a Cannon', 'Dense Populations')") # revert items with date = '[2020]' - insert_and_delete(t2020_plus.id, t_after_1999.id, "date = '[2020]'") + update_item_term(t2020_plus.id, t_after_1999.id, "date = '[2020]'") end private - def insert_and_delete(old_term_id, new_term_id, condition_sql) + def update_item_term(old_term_id, new_term_id, condition_sql) execute <<~SQL.squish WITH target AS ( - SELECT it.term_id, it.item_id, i.title + SELECT it.term_id, it.item_id FROM items i JOIN items_terms it ON i.id = it.item_id JOIN terms t ON it.term_id = t.id From 8829687012fa8c6d616fe741266d6a20f9800a97 Mon Sep 17 00:00:00 2001 From: zhouyu Date: Thu, 2 Oct 2025 10:58:32 -0700 Subject: [PATCH 09/12] Add comments --- db/migrate/20250930215317_add_two_terms.rb | 1 + .../20250930220140_add_three_ordered_terms.rb | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/db/migrate/20250930215317_add_two_terms.rb b/db/migrate/20250930215317_add_two_terms.rb index 39395ba..9ae49ac 100644 --- a/db/migrate/20250930215317_add_two_terms.rb +++ b/db/migrate/20250930215317_add_two_terms.rb @@ -1,3 +1,4 @@ +# Migration to add "Digital" and "Drawing" terms to the "Medium" facet. class AddTwoTerms < ActiveRecord::Migration[7.0] def up facet = Facet.find_by!(name: "Medium") diff --git a/db/migrate/20250930220140_add_three_ordered_terms.rb b/db/migrate/20250930220140_add_three_ordered_terms.rb index abdad5f..9f0ee83 100644 --- a/db/migrate/20250930220140_add_three_ordered_terms.rb +++ b/db/migrate/20250930220140_add_three_ordered_terms.rb @@ -1,11 +1,20 @@ +# Migration summary: +# After running `up`, the "Decade" facet will have terms: +# - "2000-2009" (ord: 11) +# - "2010-2019" (ord: 12) +# - "After 2020" (ord: 13) +# - "No Date" (ord: 14) +# - "After 1999" (ord: 15, to be removed after updating items_terms) +# After running `down`, the "Decade" facet will have: +# - "No Date" (ord: 12) +# - "After 1999" (ord: 11) +# - The three new terms will be deleted. + class AddThreeOrderedTerms < ActiveRecord::Migration[7.0] def up facet = Facet.find_by!(name: "Decade") - - # Add and remove terms from facet "Decade", and reorder them. - # The term "After 1999" is no longer needed and will be removed - # when all items_terms have been updated term = Term.find_by!(facet: facet, value: "After 1999") + # NOTE: Ensure all related items_terms records are updated before removing "After 1999" to prevent orphaned references. term.update!(ord: 15) term = Term.find_by!(facet: facet, value: "No Date") term.update!(ord: 14) From c5ba34ea8af2e2707f46baba791b49d14ff0ae32 Mon Sep 17 00:00:00 2001 From: zhouyu Date: Thu, 2 Oct 2025 11:28:25 -0700 Subject: [PATCH 10/12] Add comments, improve performace etc. --- ...0250930220504_update_term_item_relation.rb | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/db/migrate/20250930220504_update_term_item_relation.rb b/db/migrate/20250930220504_update_term_item_relation.rb index 7c5e92b..517019f 100644 --- a/db/migrate/20250930220504_update_term_item_relation.rb +++ b/db/migrate/20250930220504_update_term_item_relation.rb @@ -1,3 +1,4 @@ +# Migration to reassign items with the term "After 1999" to a newly categorized term. class UpdateTermItemRelation < ActiveRecord::Migration[7.0] def up facet = Facet.find_by!(name: 'Decade') @@ -25,16 +26,16 @@ def up end if invalid_items.any? - Rails.logger.warn("Skipped #{invalid_items.size} items due to invalid or missing dates. Example: #{invalid_items.first(10).map { |i| "ID #{i[:id]}: '#{i[:date]}'" }.join(', ')}") + Rails.logger.warn("Skipped #{invalid_items.size} items due to invalid or missing dates. Example: #{invalid_items.first(5).map { |i| "ID #{i[:id]}: '#{i[:date]}'" }.join(', ')}") end end def down facet = Facet.find_by!(name: 'Decade') target_term = Term.find_by!(facet: facet, value: 'After 1999') - move_term_back_to_item(facet, '2000-2009', target_term) - move_term_back_to_item(facet, '2010-2019', target_term) - move_term_back_to_item(facet, 'After 2020', target_term) + revert_term_assignment(facet, '2000-2009', target_term) + revert_term_assignment(facet, '2010-2019', target_term) + revert_term_assignment(facet, 'After 2020', target_term) end private @@ -43,27 +44,28 @@ def integer_year(val) return nil if val.nil? # Try direct integer conversion + year = nil begin - return Integer(val) + year = Integer(val) rescue ArgumentError, TypeError # Try to extract year from common date formats (e.g., "YYYY-MM-DD", "YYYY/MM/DD") if val.is_a?(String) if val =~ /\A(\d{4})[-\/]/ - return $1.to_i + year = $1.to_i end end - return nil end + return year end # Reassigns an item from the origin term to the target term, and removes the origin term from the item. def re_assign_term_to_item(item, origin_term, target_term) - item.terms << target_term unless item.terms.include?(target_term) + item.terms << target_term item.terms.delete(origin_term) end # Rolls back term assignment from origin_term_value to target_term for all items. - def move_term_back_to_item(facet, origin_term_value, target_term) + def revert_term_assignment(facet, origin_term_value, target_term) origin_term = Term.find_by!(facet: facet, value: origin_term_value) origin_term.items.find_each do |item| re_assign_term_to_item(item, origin_term, target_term) From 6717a66b4bfc46c24a052fce2dcdb05e4bd5f378 Mon Sep 17 00:00:00 2001 From: zhouyu Date: Thu, 2 Oct 2025 11:38:39 -0700 Subject: [PATCH 11/12] Add comments --- db/migrate/20250930230620_update_fix_term_item_relation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20250930230620_update_fix_term_item_relation.rb b/db/migrate/20250930230620_update_fix_term_item_relation.rb index 54ea031..e4be1d8 100644 --- a/db/migrate/20250930230620_update_fix_term_item_relation.rb +++ b/db/migrate/20250930230620_update_fix_term_item_relation.rb @@ -1,4 +1,4 @@ -# Update terms of the three items whose value is nil or not in date or year format +# Migration to update three items with nil or invalid date/year values class UpdateFixTermItemRelation < ActiveRecord::Migration[7.0] def up facet = Facet.find_by!(name: 'Decade') From fac87461287e281d5925d59dc8bee796990d9d45 Mon Sep 17 00:00:00 2001 From: zhouyu Date: Thu, 2 Oct 2025 14:16:53 -0700 Subject: [PATCH 12/12] Rename migration --- ...erm_after1999.rb => 20251001223022_delete_term_after1999.rb} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename db/migrate/{20251001223022_drop_term_after1999.rb => 20251001223022_delete_term_after1999.rb} (83%) diff --git a/db/migrate/20251001223022_drop_term_after1999.rb b/db/migrate/20251001223022_delete_term_after1999.rb similarity index 83% rename from db/migrate/20251001223022_drop_term_after1999.rb rename to db/migrate/20251001223022_delete_term_after1999.rb index 1a32ae9..1934246 100644 --- a/db/migrate/20251001223022_drop_term_after1999.rb +++ b/db/migrate/20251001223022_delete_term_after1999.rb @@ -1,4 +1,4 @@ -class DropTermAfter1999 < ActiveRecord::Migration[7.0] +class DeleteTermAfter1999 < ActiveRecord::Migration[7.0] def up facet = Facet.find_by!(name: 'Decade') exec_delete("DELETE FROM terms WHERE facet_id = #{facet.id} and value = 'After 1999' and ord = 15")