このコミットが含まれているのは:
@@ -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
|
||||
新しいイシューから参照
ユーザーをブロックする