refactor(backend): localize validation errors and consolidate schema

Replace hardcoded validation error messages with i18n keys.
Merge ALTER TABLE statements into initial CREATE TABLE definitions.
Clean up obsolete data migration scripts from schema file.
This commit is contained in:
2026-05-03 12:16:26 +08:00
parent ef82fc805d
commit 043ebe392a
3 changed files with 134 additions and 494 deletions

View File

@@ -1,9 +1,3 @@
CREATE TABLE IF NOT EXISTS environments (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name text NOT NULL UNIQUE,
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0)
);
CREATE TABLE IF NOT EXISTS languages (
code text PRIMARY KEY,
name text NOT NULL,
@@ -52,27 +46,6 @@ CREATE TABLE IF NOT EXISTS entity_translations (
CREATE INDEX IF NOT EXISTS entity_translations_lookup_idx
ON entity_translations (entity_type, entity_id, field_name, locale);
ALTER TABLE entity_translations DROP CONSTRAINT IF EXISTS entity_translations_entity_type_check;
ALTER TABLE entity_translations ADD CONSTRAINT entity_translations_entity_type_check CHECK (
entity_type IN (
'pokemon',
'pokemon-types',
'skills',
'environments',
'favorite-things',
'item-categories',
'item-usages',
'acquisition-methods',
'items',
'maps',
'habitats',
'daily-checklist-items',
'life-tags'
)
);
ALTER TABLE entity_translations DROP CONSTRAINT IF EXISTS entity_translations_field_name_check;
ALTER TABLE entity_translations ADD CONSTRAINT entity_translations_field_name_check CHECK (field_name IN ('name', 'title', 'details', 'genus'));
CREATE TABLE IF NOT EXISTS users (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
email text NOT NULL UNIQUE,
@@ -88,11 +61,6 @@ CREATE TABLE IF NOT EXISTS users (
CHECK (referral_code IS NULL OR referral_code ~ '^[A-Z0-9]{8,16}$')
);
ALTER TABLE users ADD COLUMN IF NOT EXISTS referral_code text;
ALTER TABLE users ADD COLUMN IF NOT EXISTS referred_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE users DROP CONSTRAINT IF EXISTS users_referral_code_check;
ALTER TABLE users ADD CONSTRAINT users_referral_code_check CHECK (referral_code IS NULL OR referral_code ~ '^[A-Z0-9]{8,16}$');
CREATE UNIQUE INDEX IF NOT EXISTS users_referral_code_idx
ON users(referral_code)
WHERE referral_code IS NOT NULL;
@@ -100,6 +68,16 @@ CREATE UNIQUE INDEX IF NOT EXISTS users_referral_code_idx
CREATE INDEX IF NOT EXISTS users_referred_by_user_id_idx
ON users(referred_by_user_id);
CREATE TABLE IF NOT EXISTS environments (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name text NOT NULL UNIQUE,
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 roles (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
key text NOT NULL UNIQUE,
@@ -114,11 +92,6 @@ CREATE TABLE IF NOT EXISTS roles (
CHECK (length(name) BETWEEN 1 AND 80)
);
ALTER TABLE roles ADD COLUMN IF NOT EXISTS description text NOT NULL DEFAULT '';
ALTER TABLE roles ADD COLUMN IF NOT EXISTS level integer NOT NULL DEFAULT 0 CHECK (level >= 0);
ALTER TABLE roles ADD COLUMN IF NOT EXISTS enabled boolean NOT NULL DEFAULT true;
ALTER TABLE roles ADD COLUMN IF NOT EXISTS system_role boolean NOT NULL DEFAULT false;
CREATE INDEX IF NOT EXISTS roles_level_idx
ON roles(level DESC, id);
@@ -137,11 +110,6 @@ CREATE TABLE IF NOT EXISTS permissions (
CHECK (length(category) BETWEEN 1 AND 80)
);
ALTER TABLE permissions ADD COLUMN IF NOT EXISTS description text NOT NULL DEFAULT '';
ALTER TABLE permissions ADD COLUMN IF NOT EXISTS category text NOT NULL DEFAULT 'General';
ALTER TABLE permissions ADD COLUMN IF NOT EXISTS enabled boolean NOT NULL DEFAULT true;
ALTER TABLE permissions ADD COLUMN IF NOT EXISTS system_permission boolean NOT NULL DEFAULT false;
CREATE INDEX IF NOT EXISTS permissions_category_idx
ON permissions(category, key);
@@ -227,9 +195,7 @@ VALUES
('discussions.comments.create', 'Create discussion comments', 'Create entity discussion comments and replies.', 'Discussions', true),
('discussions.comments.delete', 'Delete own discussion comments', 'Delete own entity discussion comments.', 'Discussions', true),
('discussions.comments.delete-any', 'Delete any discussion comment', 'Delete any entity discussion comment.', 'Discussions', true)
ON CONFLICT (key) DO UPDATE
SET system_permission = true
WHERE permissions.system_permission = false;
ON CONFLICT (key) DO NOTHING;
INSERT INTO roles (key, name, description, level, enabled, system_role)
VALUES
@@ -238,9 +204,7 @@ VALUES
('editor', 'Editor', 'Wiki editor with content creation, update, sorting and community permissions.', 500, true, true),
('member', 'Member', 'Community member with Life and discussion permissions.', 100, true, true),
('viewer', 'Viewer', 'Read-only role for explicit access grouping.', 0, true, true)
ON CONFLICT (key) DO UPDATE
SET system_role = true
WHERE roles.system_role = false;
ON CONFLICT (key) DO NOTHING;
INSERT INTO role_permissions (role_id, permission_id)
SELECT r.id, p.id
@@ -506,11 +470,6 @@ CREATE TABLE IF NOT EXISTS life_posts (
updated_at timestamptz NOT NULL DEFAULT now()
);
ALTER TABLE life_posts DROP COLUMN IF EXISTS link_url;
ALTER TABLE life_posts DROP COLUMN IF EXISTS link_title;
ALTER TABLE life_posts ADD COLUMN IF NOT EXISTS deleted_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE life_posts ADD COLUMN IF NOT EXISTS deleted_at timestamptz;
CREATE INDEX IF NOT EXISTS life_posts_created_at_idx
ON life_posts(created_at DESC, id DESC);
@@ -561,23 +520,31 @@ CREATE TABLE IF NOT EXISTS skills (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name text NOT NULL UNIQUE,
has_item_drop boolean NOT NULL DEFAULT false,
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0)
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()
);
ALTER TABLE skills DROP COLUMN IF EXISTS subcategory;
ALTER TABLE skills ADD COLUMN IF NOT EXISTS has_item_drop boolean NOT NULL DEFAULT false;
CREATE UNIQUE INDEX IF NOT EXISTS skills_name_key ON skills(name);
CREATE TABLE IF NOT EXISTS favorite_things (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name text NOT NULL UNIQUE,
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0)
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 pokemon_types (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name text NOT NULL UNIQUE,
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0)
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 pokemon (
@@ -601,7 +568,11 @@ CREATE TABLE IF NOT EXISTS pokemon (
image_version text NOT NULL DEFAULT '',
image_variant text NOT NULL DEFAULT '',
image_description text NOT NULL DEFAULT '',
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0)
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 pokemon_pokemon_types (
@@ -627,19 +598,31 @@ CREATE TABLE IF NOT EXISTS pokemon_favorite_things (
CREATE TABLE IF NOT EXISTS item_categories (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name text NOT NULL UNIQUE,
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0)
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 item_usages (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name text NOT NULL UNIQUE,
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0)
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 acquisition_methods (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name text NOT NULL UNIQUE,
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0)
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 items (
@@ -653,62 +636,29 @@ CREATE TABLE IF NOT EXISTS items (
no_recipe boolean NOT NULL DEFAULT false,
is_event_item boolean NOT NULL DEFAULT false,
image_path text NOT NULL DEFAULT '',
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0)
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()
);
ALTER TABLE items ALTER COLUMN usage_id DROP NOT NULL;
ALTER TABLE items ADD COLUMN IF NOT EXISTS no_recipe boolean NOT NULL DEFAULT false;
ALTER TABLE items ADD COLUMN IF NOT EXISTS is_event_item boolean NOT NULL DEFAULT false;
ALTER TABLE items ADD COLUMN IF NOT EXISTS image_path text NOT NULL DEFAULT '';
ALTER TABLE items DROP COLUMN IF EXISTS no_habitat;
CREATE TABLE IF NOT EXISTS recipes (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
item_id integer NOT NULL UNIQUE REFERENCES items(id),
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0)
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()
);
ALTER TABLE recipes ADD COLUMN IF NOT EXISTS item_id integer REFERENCES items(id);
DO $$
BEGIN
IF EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_name = 'items'
AND column_name = 'recipe_id'
) THEN
EXECUTE '
UPDATE recipes r
SET item_id = linked.item_id
FROM (
SELECT DISTINCT ON (recipe_id) recipe_id, id AS item_id
FROM items
WHERE recipe_id IS NOT NULL
ORDER BY recipe_id, id
) linked
WHERE r.id = linked.recipe_id
AND r.item_id IS NULL
';
END IF;
END $$;
DELETE FROM recipes WHERE item_id IS NULL;
ALTER TABLE recipes ALTER COLUMN item_id SET NOT NULL;
CREATE UNIQUE INDEX IF NOT EXISTS recipes_item_id_key ON recipes(item_id);
ALTER TABLE recipes DROP COLUMN IF EXISTS name;
ALTER TABLE items DROP COLUMN IF EXISTS recipe_id;
CREATE TABLE IF NOT EXISTS recipe_acquisition_methods (
recipe_id integer NOT NULL REFERENCES recipes(id) ON DELETE CASCADE,
acquisition_method_id integer NOT NULL REFERENCES acquisition_methods(id),
PRIMARY KEY (recipe_id, acquisition_method_id)
);
DROP TABLE IF EXISTS item_item_tags;
DROP TABLE IF EXISTS item_tags;
CREATE TABLE IF NOT EXISTS item_acquisition_methods (
item_id integer NOT NULL REFERENCES items(id) ON DELETE CASCADE,
acquisition_method_id integer NOT NULL REFERENCES acquisition_methods(id),
@@ -739,7 +689,11 @@ CREATE TABLE IF NOT EXISTS recipe_materials (
CREATE TABLE IF NOT EXISTS maps (
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name text NOT NULL UNIQUE,
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0)
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 habitats (
@@ -747,7 +701,11 @@ CREATE TABLE IF NOT EXISTS habitats (
name text NOT NULL UNIQUE,
is_event_item boolean NOT NULL DEFAULT false,
image_path text NOT NULL DEFAULT '',
sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0)
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 habitat_recipe_items (
@@ -767,236 +725,6 @@ CREATE TABLE IF NOT EXISTS habitat_pokemon (
PRIMARY KEY (habitat_id, pokemon_id, map_id, time_of_day, weather)
);
ALTER TABLE environments ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE environments ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE environments ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE environments ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE environments ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE skills ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE skills ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE skills ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE skills ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE skills ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE favorite_things ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE favorite_things ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE favorite_things ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE favorite_things ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE favorite_things ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE pokemon_types ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE pokemon_types ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE pokemon_types ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE pokemon_types ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE pokemon_types ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS display_id integer;
UPDATE pokemon SET display_id = id WHERE display_id IS NULL;
ALTER TABLE pokemon ALTER COLUMN display_id SET NOT NULL;
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS is_event_item boolean NOT NULL DEFAULT false;
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS genus text NOT NULL DEFAULT '';
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS details text NOT NULL DEFAULT '';
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS height_inches double precision NOT NULL DEFAULT 0 CHECK (height_inches >= 0);
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS weight_pounds double precision NOT NULL DEFAULT 0 CHECK (weight_pounds >= 0);
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS hp integer NOT NULL DEFAULT 0 CHECK (hp >= 0);
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS attack integer NOT NULL DEFAULT 0 CHECK (attack >= 0);
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS defense integer NOT NULL DEFAULT 0 CHECK (defense >= 0);
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS special_attack integer NOT NULL DEFAULT 0 CHECK (special_attack >= 0);
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS special_defense integer NOT NULL DEFAULT 0 CHECK (special_defense >= 0);
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS speed integer NOT NULL DEFAULT 0 CHECK (speed >= 0);
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS image_path text NOT NULL DEFAULT '';
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS image_style text NOT NULL DEFAULT '';
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS image_version text NOT NULL DEFAULT '';
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS image_variant text NOT NULL DEFAULT '';
ALTER TABLE pokemon ADD COLUMN IF NOT EXISTS image_description text NOT NULL DEFAULT '';
ALTER TABLE life_tags ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE life_tags ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE life_tags ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE life_tags ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE life_tags ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE item_categories ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE item_categories ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE item_categories ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE item_categories ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE item_categories ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE item_usages ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE item_usages ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE item_usages ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE item_usages ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE item_usages ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE acquisition_methods ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE acquisition_methods ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE acquisition_methods ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE acquisition_methods ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE acquisition_methods ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE items ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE items ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE items ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE items ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE items ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE items ADD COLUMN IF NOT EXISTS is_event_item boolean NOT NULL DEFAULT false;
ALTER TABLE recipes ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE recipes ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE recipes ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE recipes ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE recipes ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE maps ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE maps ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE maps ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE maps ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE maps ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE habitats ADD COLUMN IF NOT EXISTS created_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE habitats ADD COLUMN IF NOT EXISTS updated_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE habitats ADD COLUMN IF NOT EXISTS created_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE habitats ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
ALTER TABLE habitats ADD COLUMN IF NOT EXISTS sort_order integer NOT NULL DEFAULT 0 CHECK (sort_order >= 0);
ALTER TABLE habitats ADD COLUMN IF NOT EXISTS is_event_item boolean NOT NULL DEFAULT false;
ALTER TABLE habitats ADD COLUMN IF NOT EXISTS image_path text NOT NULL DEFAULT '';
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM environments
WHERE sort_order = 0
)
UPDATE environments target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM skills
WHERE sort_order = 0
)
UPDATE skills target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM favorite_things
WHERE sort_order = 0
)
UPDATE favorite_things target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM pokemon_types
WHERE sort_order = 0
)
UPDATE pokemon_types target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM pokemon
WHERE sort_order = 0
)
UPDATE pokemon target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM life_tags
WHERE sort_order = 0
)
UPDATE life_tags target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM item_categories
WHERE sort_order = 0
)
UPDATE item_categories target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM item_usages
WHERE sort_order = 0
)
UPDATE item_usages target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM acquisition_methods
WHERE sort_order = 0
)
UPDATE acquisition_methods target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM items
WHERE sort_order = 0
)
UPDATE items target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM recipes
WHERE sort_order = 0
)
UPDATE recipes target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM maps
WHERE sort_order = 0
)
UPDATE maps target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
WITH ordered AS (
SELECT id, (row_number() OVER (ORDER BY created_at, id) * 10)::integer AS next_sort_order
FROM habitats
WHERE sort_order = 0
)
UPDATE habitats target
SET sort_order = ordered.next_sort_order
FROM ordered
WHERE target.id = ordered.id;
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);
CREATE INDEX IF NOT EXISTS favorite_things_sort_order_idx ON favorite_things(sort_order, id);
@@ -1022,8 +750,6 @@ CREATE TABLE IF NOT EXISTS wiki_edit_logs (
created_at timestamptz NOT NULL DEFAULT now()
);
ALTER TABLE wiki_edit_logs ADD COLUMN IF NOT EXISTS changes jsonb NOT NULL DEFAULT '[]'::jsonb;
CREATE INDEX IF NOT EXISTS wiki_edit_logs_entity_idx
ON wiki_edit_logs(entity_type, entity_id, created_at DESC);
@@ -1045,16 +771,6 @@ CREATE TABLE IF NOT EXISTS entity_image_uploads (
CHECK (path !~ '(^/|\\.\\.)')
);
ALTER TABLE entity_image_uploads DROP CONSTRAINT IF EXISTS entity_image_uploads_entity_type_check;
ALTER TABLE entity_image_uploads ADD CONSTRAINT entity_image_uploads_entity_type_check CHECK (
entity_type IN ('pokemon', 'items', 'habitats')
);
ALTER TABLE entity_image_uploads DROP CONSTRAINT IF EXISTS entity_image_uploads_mime_type_check;
ALTER TABLE entity_image_uploads ADD CONSTRAINT entity_image_uploads_mime_type_check CHECK (
mime_type IN ('image/png', 'image/jpeg', 'image/webp', 'image/gif')
);
CREATE INDEX IF NOT EXISTS entity_image_uploads_entity_idx
ON entity_image_uploads(entity_type, entity_id, created_at DESC, id DESC);
@@ -1074,15 +790,6 @@ CREATE TABLE IF NOT EXISTS entity_discussion_comments (
updated_at timestamptz NOT NULL DEFAULT now()
);
ALTER TABLE entity_discussion_comments DROP CONSTRAINT IF EXISTS entity_discussion_comments_entity_type_check;
ALTER TABLE entity_discussion_comments ADD CONSTRAINT entity_discussion_comments_entity_type_check CHECK (
entity_type IN ('pokemon', 'items', 'recipes', 'habitats')
);
ALTER TABLE entity_discussion_comments ADD COLUMN IF NOT EXISTS deleted_by_user_id integer REFERENCES users(id) ON DELETE SET NULL;
ALTER TABLE entity_discussion_comments ADD COLUMN IF NOT EXISTS deleted_at timestamptz;
ALTER TABLE entity_discussion_comments ADD COLUMN IF NOT EXISTS updated_at timestamptz NOT NULL DEFAULT now();
CREATE INDEX IF NOT EXISTS entity_discussion_comments_entity_idx
ON entity_discussion_comments(entity_type, entity_id, created_at, id);