**本番 DB のバックアップをかならずすること** Reviewed-on: #420 Co-authored-by: miteruzo <miteruzo@naver.com>
このコミットはプルリクエスト #420 でマージされました。
このコミットが含まれているのは:
@@ -0,0 +1,54 @@
|
||||
class CreateExternalTags < ActiveRecord::Migration[8.0]
|
||||
def up
|
||||
create_table :external_tags do |t|
|
||||
t.string :platform, limit: 16, null: false
|
||||
t.string :name, limit: 255, null: false
|
||||
t.integer :post_count, null: false, default: 0
|
||||
t.datetime :created_at, null: false
|
||||
|
||||
t.index [:platform, :name], unique: true
|
||||
end
|
||||
|
||||
execute <<~SQL
|
||||
INSERT INTO
|
||||
external_tags(id, platform, name, post_count, created_at)
|
||||
SELECT
|
||||
t.id
|
||||
, 'nico' AS platform
|
||||
, SUBSTR(tn.name, 6) AS name
|
||||
, t.post_count
|
||||
, t.created_at
|
||||
FROM
|
||||
tags t
|
||||
INNER JOIN
|
||||
tag_names tn
|
||||
ON
|
||||
tn.id = t.tag_name_id
|
||||
AND t.category = 'nico'
|
||||
SQL
|
||||
|
||||
execute <<~SQL
|
||||
INSERT INTO
|
||||
external_tags(id, platform, name, post_count, created_at)
|
||||
SELECT
|
||||
ntv.tag_id
|
||||
, 'nico' AS platform
|
||||
, SUBSTR(ntv.name, 6) AS name
|
||||
, 0 AS post_count
|
||||
, ntv.created_at
|
||||
FROM
|
||||
nico_tag_versions ntv
|
||||
LEFT JOIN
|
||||
external_tags et
|
||||
ON
|
||||
et.id = ntv.tag_id
|
||||
WHERE
|
||||
ntv.version_no = 1
|
||||
AND et.id IS NULL
|
||||
SQL
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :external_tags
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,29 @@
|
||||
class CreatePostExternalTags < ActiveRecord::Migration[8.0]
|
||||
def up
|
||||
create_table :post_external_tags, primary_key: [:post_id, :external_tag_id] do |t|
|
||||
t.references :post, null: false, index: false, foreign_key: true
|
||||
t.references :external_tag, null: false, foreign_key: true
|
||||
t.datetime :created_at, null: false
|
||||
end
|
||||
|
||||
execute <<~SQL
|
||||
INSERT INTO
|
||||
post_external_tags(post_id, external_tag_id, created_at)
|
||||
SELECT
|
||||
pt.post_id
|
||||
, pt.tag_id AS external_tag_id
|
||||
, pt.created_at
|
||||
FROM
|
||||
post_tags pt
|
||||
INNER JOIN
|
||||
tags t
|
||||
ON
|
||||
pt.tag_id = t.id
|
||||
AND t.category = 'nico'
|
||||
SQL
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :post_external_tags
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
class ChangeForeignKeyOnNicoTagRelations < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
remove_foreign_key :nico_tag_relations, :tags, column: :nico_tag_id
|
||||
add_foreign_key :nico_tag_relations, :external_tags, column: :nico_tag_id
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,199 @@
|
||||
class MigrateExternalTags < ActiveRecord::Migration[8.0]
|
||||
class MigrationPostVersion < ActiveRecord::Base
|
||||
self.table_name = 'post_versions'
|
||||
end
|
||||
|
||||
def up
|
||||
x = connection.select_value(<<~SQL)
|
||||
SELECT
|
||||
COUNT(0)
|
||||
FROM
|
||||
post_tag_sections pts
|
||||
INNER JOIN
|
||||
tags t
|
||||
ON
|
||||
t.id = pts.tag_id
|
||||
WHERE
|
||||
t.category = 'nico'
|
||||
SQL
|
||||
if x > 0
|
||||
raise "post_tag_sections に #{ x } 件のチンカスがあります!"
|
||||
end
|
||||
|
||||
x = connection.select_value(<<~SQL)
|
||||
SELECT
|
||||
COUNT(0)
|
||||
FROM
|
||||
materials m
|
||||
INNER JOIN
|
||||
tags t
|
||||
ON
|
||||
t.id = m.tag_id
|
||||
WHERE
|
||||
t.category = 'nico'
|
||||
SQL
|
||||
if x > 0
|
||||
raise "materials に #{ x } 件のチンカスがあります!"
|
||||
end
|
||||
|
||||
x = connection.select_value(<<~SQL)
|
||||
SELECT
|
||||
COUNT(0)
|
||||
FROM
|
||||
tag_implications ti
|
||||
INNER JOIN
|
||||
tags t
|
||||
ON
|
||||
t.id = ti.tag_id
|
||||
OR t.id = ti.parent_tag_id
|
||||
WHERE
|
||||
t.category = 'nico'
|
||||
SQL
|
||||
if x > 0
|
||||
raise "tag_implications に #{ x } 件のチンカスがあります!"
|
||||
end
|
||||
|
||||
execute <<~SQL
|
||||
DELETE
|
||||
ts
|
||||
FROM
|
||||
tag_similarities ts
|
||||
INNER JOIN
|
||||
tags t
|
||||
ON
|
||||
t.category = 'nico'
|
||||
AND (t.id = ts.tag_id
|
||||
OR t.id = ts.target_tag_id)
|
||||
SQL
|
||||
|
||||
execute <<~SQL
|
||||
DELETE
|
||||
tset
|
||||
FROM
|
||||
theatre_skip_event_tags tset
|
||||
INNER JOIN
|
||||
tags t
|
||||
ON
|
||||
t.category = 'nico'
|
||||
AND t.id = tset.tag_id
|
||||
SQL
|
||||
|
||||
remove_check_constraint :post_versions, name: 'chk_post_versions_tags_json_schema'
|
||||
|
||||
say_with_time 'Migrate post_versions.tags_json' do
|
||||
count = 0
|
||||
|
||||
MigrationPostVersion.find_each(batch_size: 500) do |version|
|
||||
tags = version.tags_json.map do |tag|
|
||||
if tag.fetch('category') == 'nico'
|
||||
{ 'external_tag_id' => tag.fetch('id') }
|
||||
else
|
||||
{ 'tag_id' => tag.fetch('id'),
|
||||
'version_no' => tag.fetch('version_no'),
|
||||
'name' => tag.fetch('name'),
|
||||
'category' => tag.fetch('category'),
|
||||
'sections' => tag.fetch('sections') }
|
||||
end
|
||||
end
|
||||
|
||||
version.update_columns(tags_json: tags)
|
||||
count += 1
|
||||
end
|
||||
|
||||
count
|
||||
end
|
||||
|
||||
add_tags_json_constraint!
|
||||
|
||||
tag_name_ids = connection.select_values(<<~SQL)
|
||||
SELECT
|
||||
tag_name_id
|
||||
FROM
|
||||
tags
|
||||
WHERE
|
||||
category = 'nico'
|
||||
SQL
|
||||
|
||||
connection.transaction do
|
||||
execute <<~SQL
|
||||
DELETE
|
||||
pt
|
||||
FROM
|
||||
post_tags pt
|
||||
INNER JOIN
|
||||
tags t
|
||||
ON
|
||||
t.category = 'nico'
|
||||
AND t.id = pt.tag_id
|
||||
SQL
|
||||
|
||||
execute <<~SQL
|
||||
DELETE
|
||||
FROM
|
||||
tags
|
||||
WHERE
|
||||
category = 'nico'
|
||||
SQL
|
||||
|
||||
unless tag_name_ids.empty?
|
||||
execute <<~SQL
|
||||
DELETE
|
||||
FROM
|
||||
tag_names
|
||||
WHERE
|
||||
id IN (#{ tag_name_ids.join(', ') })
|
||||
SQL
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
raise ActiveRecord::IrreversibleMigration, '戻せません.'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def add_tags_json_constraint!
|
||||
schema = { type: 'array',
|
||||
items: { oneOf: [internal_tag_schema, external_tag_schema] } }
|
||||
|
||||
quoted_schema = connection.quote(JSON.generate(schema))
|
||||
|
||||
add_check_constraint :post_versions,
|
||||
"JSON_SCHEMA_VALID(#{ quoted_schema }, tags_json)",
|
||||
name: 'chk_post_versions_tags_json_schema'
|
||||
end
|
||||
|
||||
def internal_tag_schema
|
||||
{ type: 'object',
|
||||
properties: { tag_id: { type: 'integer', minimum: 1 },
|
||||
version_no: { type: 'integer', minimum: 1 },
|
||||
name: { type: 'string', minLength: 1 },
|
||||
category: { type: 'string',
|
||||
enum: ['deerjikist',
|
||||
'meme',
|
||||
'character',
|
||||
'general',
|
||||
'material',
|
||||
'meta'] },
|
||||
sections: sections_schema },
|
||||
required: ['tag_id', 'version_no', 'sections'],
|
||||
additionalProperties: false }
|
||||
end
|
||||
|
||||
def external_tag_schema
|
||||
{ type: 'object',
|
||||
properties: { external_tag_id: { type: 'integer', minimum: 1 } },
|
||||
required: ['external_tag_id'],
|
||||
additionalProperties: false }
|
||||
end
|
||||
|
||||
def sections_schema
|
||||
{ type: 'array',
|
||||
items: { type: 'object',
|
||||
properties: { begin_ms: { type: 'integer', minimum: 0 },
|
||||
end_ms: { type: ['integer', 'null'], minimum: 0 } },
|
||||
required: ['begin_ms', 'end_ms'],
|
||||
additionalProperties: false } }
|
||||
end
|
||||
end
|
||||
生成ファイル
+20
-3
@@ -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_09_21_030000) do
|
||||
ActiveRecord::Schema[8.0].define(version: 2026_09_21_230000) 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
|
||||
@@ -48,6 +48,14 @@ ActiveRecord::Schema[8.0].define(version: 2026_09_21_030000) do
|
||||
t.index ["tag_id"], name: "index_deerjikists_on_tag_id"
|
||||
end
|
||||
|
||||
create_table "external_tags", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
|
||||
t.string "platform", limit: 16, null: false
|
||||
t.string "name", null: false
|
||||
t.integer "post_count", default: 0, null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.index ["platform", "name"], name: "index_external_tags_on_platform_and_name", unique: true
|
||||
end
|
||||
|
||||
create_table "gekanator_ai_runs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
|
||||
t.string "model", null: false
|
||||
t.integer "input_tokens", default: 0, null: false
|
||||
@@ -281,6 +289,13 @@ ActiveRecord::Schema[8.0].define(version: 2026_09_21_030000) do
|
||||
t.check_constraint "`version_no` > 0", name: "nico_tag_versions_version_no_positive"
|
||||
end
|
||||
|
||||
create_table "post_external_tags", primary_key: ["post_id", "external_tag_id"], charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
|
||||
t.bigint "post_id", null: false
|
||||
t.bigint "external_tag_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.index ["external_tag_id"], name: "index_post_external_tags_on_external_tag_id"
|
||||
end
|
||||
|
||||
create_table "post_implications", primary_key: ["post_id", "parent_post_id"], charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
|
||||
t.bigint "post_id", null: false
|
||||
t.bigint "parent_post_id", null: false
|
||||
@@ -352,7 +367,7 @@ ActiveRecord::Schema[8.0].define(version: 2026_09_21_030000) do
|
||||
t.check_constraint "(`video_ms` is null) or (`video_ms` > 0)", name: "chk_post_versions_video_ms_positive"
|
||||
t.check_constraint "`event_type` in (_utf8mb4'create',_utf8mb4'update',_utf8mb4'discard',_utf8mb4'restore')", name: "post_versions_event_type_valid"
|
||||
t.check_constraint "`version_no` > 0", name: "post_versions_version_no_positive"
|
||||
t.check_constraint "json_schema_valid(_utf8mb4'{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"id\":{\"type\":\"integer\",\"minimum\":1},\"version_no\":{\"type\":\"integer\",\"minimum\":1},\"name\":{\"type\":\"string\",\"minLength\":1},\"category\":{\"type\":\"string\",\"enum\":[\"deerjikist\",\"meme\",\"character\",\"general\",\"material\",\"meta\",\"nico\"]},\"sections\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"begin_ms\":{\"type\":\"integer\",\"minimum\":0},\"end_ms\":{\"type\":[\"integer\",\"null\"],\"minimum\":0}},\"required\":[\"begin_ms\",\"end_ms\"],\"additionalProperties\":false}}},\"required\":[\"id\",\"version_no\",\"name\",\"category\",\"sections\"],\"additionalProperties\":false}}',`tags_json`)", name: "chk_post_versions_tags_json_schema"
|
||||
t.check_constraint "json_schema_valid(_utf8mb4'{\"type\":\"array\",\"items\":{\"oneOf\":[{\"type\":\"object\",\"properties\":{\"tag_id\":{\"type\":\"integer\",\"minimum\":1},\"version_no\":{\"type\":\"integer\",\"minimum\":1},\"name\":{\"type\":\"string\",\"minLength\":1},\"category\":{\"type\":\"string\",\"enum\":[\"deerjikist\",\"meme\",\"character\",\"general\",\"material\",\"meta\"]},\"sections\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"begin_ms\":{\"type\":\"integer\",\"minimum\":0},\"end_ms\":{\"type\":[\"integer\",\"null\"],\"minimum\":0}},\"required\":[\"begin_ms\",\"end_ms\"],\"additionalProperties\":false}}},\"required\":[\"tag_id\",\"version_no\",\"sections\"],\"additionalProperties\":false},{\"type\":\"object\",\"properties\":{\"external_tag_id\":{\"type\":\"integer\",\"minimum\":1}},\"required\":[\"external_tag_id\"],\"additionalProperties\":false}]}}',`tags_json`)", name: "chk_post_versions_tags_json_schema"
|
||||
end
|
||||
|
||||
create_table "posts", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
|
||||
@@ -700,9 +715,11 @@ ActiveRecord::Schema[8.0].define(version: 2026_09_21_030000) do
|
||||
add_foreign_key "materials", "tags"
|
||||
add_foreign_key "materials", "users", column: "created_by_user_id"
|
||||
add_foreign_key "materials", "users", column: "updated_by_user_id"
|
||||
add_foreign_key "nico_tag_relations", "external_tags", column: "nico_tag_id"
|
||||
add_foreign_key "nico_tag_relations", "tags"
|
||||
add_foreign_key "nico_tag_relations", "tags", column: "nico_tag_id"
|
||||
add_foreign_key "nico_tag_versions", "users", column: "created_by_user_id"
|
||||
add_foreign_key "post_external_tags", "external_tags"
|
||||
add_foreign_key "post_external_tags", "posts"
|
||||
add_foreign_key "post_implications", "posts"
|
||||
add_foreign_key "post_implications", "posts", column: "parent_post_id"
|
||||
add_foreign_key "post_similarities", "posts"
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする