refactor(items): merge ancient artifacts into items data model

Migrate ancient artifacts to items table using a category key.
Consolidate detail and edit views into ItemDetail and ItemEdit.
Update API, search, and data tools to reflect unified structure.
This commit is contained in:
2026-05-05 10:46:14 +08:00
parent 839a24566b
commit 5a83a73108
11 changed files with 526 additions and 594 deletions

View File

@@ -977,6 +977,7 @@ CREATE TABLE IF NOT EXISTS items (
name text NOT NULL UNIQUE,
details text NOT NULL DEFAULT '',
base_price integer,
ancient_artifact_category_key text,
category_key text NOT NULL DEFAULT 'other',
usage_key text,
category_id integer REFERENCES item_categories(id),
@@ -1006,22 +1007,13 @@ CREATE TABLE IF NOT EXISTS items (
'key-items',
'other'
)),
CHECK (
ancient_artifact_category_key IS NULL
OR ancient_artifact_category_key IN ('lost-relics-l', 'lost-relics-s', 'fossils')
),
CHECK (usage_key IS NULL OR usage_key IN ('decoration', 'relaxation', 'toy', 'road'))
);
CREATE TABLE IF NOT EXISTS ancient_artifacts (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name text NOT NULL UNIQUE,
details text NOT NULL DEFAULT '',
category_key text NOT NULL CHECK (category_key IN ('lost-relics-l', 'lost-relics-s', 'fossils')),
image_path text NOT NULL DEFAULT '',
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0),
created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL,
updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL,
created_at timestamptz NOT NULL DEFAULT now(),
updated_at timestamptz NOT NULL DEFAULT now()
);
CREATE TABLE IF NOT EXISTS recipes (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
item_id integer NOT NULL UNIQUE REFERENCES items(id),
@@ -1050,12 +1042,6 @@ CREATE TABLE IF NOT EXISTS item_favorite_things (
PRIMARY KEY (item_id, favorite_thing_id)
);
CREATE TABLE IF NOT EXISTS ancient_artifact_favorite_things (
ancient_artifact_id integer NOT NULL REFERENCES ancient_artifacts(id) ON DELETE CASCADE,
favorite_thing_id integer NOT NULL REFERENCES favorite_things(id),
PRIMARY KEY (ancient_artifact_id, favorite_thing_id)
);
CREATE TABLE IF NOT EXISTS pokemon_skill_item_drops (
pokemon_id integer NOT NULL,
skill_id integer NOT NULL,
@@ -1222,6 +1208,7 @@ ALTER TABLE life_tags
ALTER TABLE items
ADD COLUMN IF NOT EXISTS details text NOT NULL DEFAULT '',
ADD COLUMN IF NOT EXISTS base_price integer,
ADD COLUMN IF NOT EXISTS ancient_artifact_category_key text,
ADD COLUMN IF NOT EXISTS category_key text,
ADD COLUMN IF NOT EXISTS usage_key text;
@@ -1229,9 +1216,6 @@ UPDATE items
SET base_price = NULL
WHERE base_price < 0;
ALTER TABLE ancient_artifacts
ADD COLUMN IF NOT EXISTS image_path text NOT NULL DEFAULT '';
DO $$
BEGIN
IF EXISTS (
@@ -1308,11 +1292,16 @@ ALTER TABLE items
ALTER TABLE items
DROP CONSTRAINT IF EXISTS items_display_id_positive,
DROP CONSTRAINT IF EXISTS items_base_price_check,
DROP CONSTRAINT IF EXISTS items_ancient_artifact_category_key_check,
DROP CONSTRAINT IF EXISTS items_category_key_check,
DROP CONSTRAINT IF EXISTS items_usage_key_check;
ALTER TABLE items
ADD CONSTRAINT items_base_price_check CHECK (base_price IS NULL OR base_price >= 0),
ADD CONSTRAINT items_ancient_artifact_category_key_check CHECK (
ancient_artifact_category_key IS NULL
OR ancient_artifact_category_key IN ('lost-relics-l', 'lost-relics-s', 'fossils')
),
ADD CONSTRAINT items_category_key_check CHECK (category_key IN (
'furniture',
'misc',
@@ -1329,19 +1318,104 @@ ALTER TABLE items
)),
ADD CONSTRAINT items_usage_key_check CHECK (usage_key IS NULL OR usage_key IN ('decoration', 'relaxation', 'toy', 'road'));
DO $$
BEGIN
IF to_regclass('ancient_artifacts') IS NOT NULL THEN
ALTER TABLE ancient_artifacts
ADD COLUMN IF NOT EXISTS image_path text NOT NULL DEFAULT '';
CREATE TEMP TABLE migrated_ancient_artifact_items (
old_id integer PRIMARY KEY,
item_id integer NOT NULL
) ON COMMIT DROP;
INSERT INTO items (
name,
details,
ancient_artifact_category_key,
category_key,
image_path,
sort_order,
created_by_user_id,
updated_by_user_id,
created_at,
updated_at
)
SELECT
a.name,
a.details,
a.category_key,
'other',
a.image_path,
a.sort_order,
a.created_by_user_id,
a.updated_by_user_id,
a.created_at,
a.updated_at
FROM ancient_artifacts a
ON CONFLICT (name) DO UPDATE
SET ancient_artifact_category_key = EXCLUDED.ancient_artifact_category_key,
details = CASE WHEN items.details = '' THEN EXCLUDED.details ELSE items.details END,
image_path = CASE WHEN items.image_path = '' THEN EXCLUDED.image_path ELSE items.image_path END,
updated_by_user_id = COALESCE(items.updated_by_user_id, EXCLUDED.updated_by_user_id),
updated_at = GREATEST(items.updated_at, EXCLUDED.updated_at);
INSERT INTO migrated_ancient_artifact_items (old_id, item_id)
SELECT a.id, i.id
FROM ancient_artifacts a
JOIN items i ON i.name = a.name
ON CONFLICT (old_id) DO UPDATE SET item_id = EXCLUDED.item_id;
IF to_regclass('ancient_artifact_favorite_things') IS NOT NULL THEN
INSERT INTO item_favorite_things (item_id, favorite_thing_id)
SELECT m.item_id, aft.favorite_thing_id
FROM ancient_artifact_favorite_things aft
JOIN migrated_ancient_artifact_items m ON m.old_id = aft.ancient_artifact_id
ON CONFLICT DO NOTHING;
END IF;
INSERT INTO entity_translations (entity_type, entity_id, locale, field_name, value)
SELECT 'items', m.item_id, et.locale, et.field_name, et.value
FROM entity_translations et
JOIN migrated_ancient_artifact_items m ON m.old_id = et.entity_id
WHERE et.entity_type = 'ancient-artifacts'
ON CONFLICT (entity_type, entity_id, locale, field_name) DO UPDATE
SET value = EXCLUDED.value;
UPDATE wiki_edit_logs wel
SET entity_type = 'items',
entity_id = m.item_id
FROM migrated_ancient_artifact_items m
WHERE wel.entity_type = 'ancient-artifacts'
AND wel.entity_id = m.old_id;
UPDATE entity_image_uploads eiu
SET entity_type = 'items',
entity_id = m.item_id
FROM migrated_ancient_artifact_items m
WHERE eiu.entity_type = 'ancient-artifacts'
AND eiu.entity_id = m.old_id;
UPDATE entity_discussion_comments edc
SET entity_id = m.item_id
FROM migrated_ancient_artifact_items m
WHERE edc.entity_type = 'ancient-artifacts'
AND edc.entity_id = m.old_id;
DELETE FROM entity_translations
WHERE entity_type = 'ancient-artifacts';
END IF;
END $$;
DROP INDEX IF EXISTS items_display_event_item_key;
DROP INDEX IF EXISTS items_display_order_idx;
DROP INDEX IF EXISTS ancient_artifacts_display_order_idx;
ALTER TABLE ancient_artifacts
DROP CONSTRAINT IF EXISTS ancient_artifacts_display_id_key,
DROP CONSTRAINT IF EXISTS ancient_artifacts_display_id_check;
ALTER TABLE items
DROP COLUMN IF EXISTS display_id;
ALTER TABLE ancient_artifacts
DROP COLUMN IF EXISTS display_id;
DROP TABLE IF EXISTS ancient_artifact_favorite_things;
DROP TABLE IF EXISTS ancient_artifacts;
CREATE INDEX IF NOT EXISTS environments_sort_order_idx ON environments(sort_order, id);
CREATE INDEX IF NOT EXISTS skills_sort_order_idx ON skills(sort_order, id);
@@ -1355,7 +1429,6 @@ CREATE INDEX IF NOT EXISTS item_categories_sort_order_idx ON item_categories(sor
CREATE INDEX IF NOT EXISTS item_usages_sort_order_idx ON item_usages(sort_order, id);
CREATE INDEX IF NOT EXISTS acquisition_methods_sort_order_idx ON acquisition_methods(sort_order, id);
CREATE INDEX IF NOT EXISTS items_sort_order_idx ON items(sort_order, id);
CREATE INDEX IF NOT EXISTS ancient_artifacts_sort_order_idx ON ancient_artifacts(sort_order, id);
CREATE INDEX IF NOT EXISTS recipes_sort_order_idx ON recipes(sort_order, id);
CREATE INDEX IF NOT EXISTS dish_categories_sort_order_idx ON dish_categories(sort_order, id);
CREATE INDEX IF NOT EXISTS dish_flavors_sort_order_idx ON dish_flavors(sort_order, id);