| @@ -2,15 +2,15 @@ require 'set' | |||
| class CreatePostVersions < ActiveRecord::Migration[8.0] | |||
| class Post < ApplicationRecord | |||
| class Post < ActiveRecord::Base | |||
| self.table_name = 'posts' | |||
| end | |||
| class PostTag < ApplicationRecord | |||
| class PostTag < ActiveRecord::Base | |||
| self.table_name = 'post_tags' | |||
| end | |||
| class PostVersion < ApplicationRecord | |||
| class PostVersion < ActiveRecord::Base | |||
| self.table_name = 'post_versions' | |||
| end | |||
| @@ -0,0 +1,89 @@ | |||
| class CreateTagVersions < ActiveRecord::Migration[8.0] | |||
| class Tag < ActiveRecord::Base | |||
| self.table_name = 'tags' | |||
| end | |||
| class TagName < ActiveRecord::Base | |||
| self.table_name = 'tag_names' | |||
| end | |||
| class TagImplication < ActiveRecord::Base | |||
| self.table_name = 'tag_implications' | |||
| end | |||
| class TagVersion < ActiveRecord::Base | |||
| self.table_name = 'tag_versions' | |||
| end | |||
| def up | |||
| create_table :tag_versions do |t| | |||
| t.references :tag, null: false, foreign_key: true, index: false | |||
| t.integer :version_no, null: false | |||
| t.string :event_type, null: false | |||
| t.string :name, null: false | |||
| t.string :category, null: false | |||
| t.text :aliases, null: false | |||
| t.text :parent_tag_ids, null: false | |||
| t.datetime :created_at, null: false | |||
| t.references :created_by_user, foreign_key: { to_table: :users }, index: false | |||
| t.index [:tag_id, :version_no], unique: true | |||
| t.index :created_at | |||
| t.index [:tag_id, :created_at], order: { created_at: :desc } | |||
| t.index [:created_by_user_id, :created_at], order: { created_at: :desc } | |||
| t.check_constraint 'version_no > 0', | |||
| name: 'tag_versions_version_no_positive' | |||
| end | |||
| TagVersion.reset_column_information | |||
| say_with_time 'Backfilling tag_versions' do | |||
| Tag.where(discarded_at: nil).find_in_batches(batch_size: 500) do |tags| | |||
| tag_ids = tags.map(&:id) | |||
| tag_implication_rows_by_tag_id = | |||
| TagImplication | |||
| .where(tag_id: tag_ids) | |||
| .pluck(:tag_id, :parent_tag_id) | |||
| .each_with_object(Hash.new { |h, k| h[k] = [] }) do |row, h| | |||
| h[row[0]] << row[1] | |||
| end | |||
| tag_name_rows_by_tag_id = | |||
| TagName | |||
| .joins('INNER JOIN tags ON tags.tag_name_id = tag_names.id') | |||
| .where(tags: { id: tag_ids }) | |||
| .pluck('tags.id', 'tag_names.name') | |||
| .each_with_object({ }) do |row, h| | |||
| h[row[0]] = row[1] | |||
| end | |||
| tag_alias_rows_by_tag_id = | |||
| TagName | |||
| .joins('INNER JOIN tags ON tags.tag_name_id = tag_names.canonical_id') | |||
| .where(tags: { id: tag_ids }) | |||
| .where(tag_names: { discarded_at: nil }) | |||
| .pluck('tags.id', 'tag_names.name') | |||
| .each_with_object(Hash.new { |h, k| h[k] = [] }) do |row, h| | |||
| h[row[0]] << row[1] | |||
| end | |||
| TagVersion.insert_all(tags.map { |tag| | |||
| { tag_id: tag.id, | |||
| version_no: 1, | |||
| event_type: 'create', | |||
| name: tag_name_rows_by_tag_id[tag.id], | |||
| category: tag.category, | |||
| aliases: tag_alias_rows_by_tag_id[tag.id].sort.join(' '), | |||
| parent_tag_ids: tag_implication_rows_by_tag_id[tag.id].sort.join(' '), | |||
| created_at: tag.created_at, | |||
| created_by_user_id: nil } | |||
| }) | |||
| end | |||
| end | |||
| end | |||
| def down | |||
| drop_table :tag_versions | |||
| end | |||
| end | |||
| @@ -10,7 +10,7 @@ | |||
| # | |||
| # It's strongly recommended that you check this file into your version control system. | |||
| ActiveRecord::Schema[8.0].define(version: 2026_04_09_123700) do | |||
| ActiveRecord::Schema[8.0].define(version: 2026_04_19_035400) do | |||
| create_table "active_storage_attachments", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| | |||
| t.string "name", null: false | |||
| t.string "record_type", null: false | |||
| @@ -216,6 +216,23 @@ ActiveRecord::Schema[8.0].define(version: 2026_04_09_123700) do | |||
| t.index ["target_tag_id"], name: "index_tag_similarities_on_target_tag_id" | |||
| end | |||
| create_table "tag_versions", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| | |||
| t.bigint "tag_id", null: false | |||
| t.integer "version_no", null: false | |||
| t.string "event_type", null: false | |||
| t.string "name", null: false | |||
| t.string "category", null: false | |||
| t.text "aliases", null: false | |||
| t.text "parent_tag_ids", null: false | |||
| t.datetime "created_at", null: false | |||
| t.bigint "created_by_user_id" | |||
| t.index ["created_at"], name: "index_tag_versions_on_created_at" | |||
| t.index ["created_by_user_id", "created_at"], name: "index_tag_versions_on_created_by_user_id_and_created_at", order: { created_at: :desc } | |||
| t.index ["tag_id", "created_at"], name: "index_tag_versions_on_tag_id_and_created_at", order: { created_at: :desc } | |||
| t.index ["tag_id", "version_no"], name: "index_tag_versions_on_tag_id_and_version_no", unique: true | |||
| t.check_constraint "`version_no` > 0", name: "tag_versions_version_no_positive" | |||
| end | |||
| create_table "tags", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| | |||
| t.bigint "tag_name_id", null: false | |||
| t.string "category", default: "general", null: false | |||
| @@ -394,6 +411,8 @@ ActiveRecord::Schema[8.0].define(version: 2026_04_09_123700) do | |||
| add_foreign_key "tag_names", "tag_names", column: "canonical_id" | |||
| add_foreign_key "tag_similarities", "tags" | |||
| add_foreign_key "tag_similarities", "tags", column: "target_tag_id" | |||
| add_foreign_key "tag_versions", "tags" | |||
| add_foreign_key "tag_versions", "users", column: "created_by_user_id" | |||
| add_foreign_key "tags", "tag_names" | |||
| add_foreign_key "theatre_comments", "theatres" | |||
| add_foreign_key "theatre_comments", "users" | |||