Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 35 additions & 33 deletions api/schema.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
\set ON_ERROR_STOP on

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 Bug: psql meta-command \set breaks migrate.ts execution path

\set ON_ERROR_STOP on is a psql client meta-command, not SQL. It works when the postgres Docker image runs schema.sql via psql (docker-entrypoint-initdb.d), but api/src/migrate.ts loads the file and executes it with node-postgres via pool.query(schemaSql). The server parses \set ON_ERROR_STOP on as SQL and returns syntax error at or near "", failing the entire batch. Since pnpm run start runs migrate first (package.json), this breaks app startup and any npm run migrate invocation. Fix: remove the \set line from schema.sql (the reordering alone already resolves issue #82), or strip psql meta-commands in migrate.ts before calling pool.query and wrap the batch in a transaction to get equivalent abort-on-error behavior.

Was this helpful? React with 👍 / 👎


CREATE EXTENSION IF NOT EXISTS pgcrypto;

CREATE TABLE IF NOT EXISTS accounts (
Expand Down Expand Up @@ -104,6 +106,39 @@ FROM characters leader
WHERE leader.id = cl.leader_character_id
AND cl.alignment NOT IN ('citizen', 'criminal');

ALTER TABLE characters
ADD COLUMN IF NOT EXISTS clan_id UUID REFERENCES clans(id) ON DELETE SET NULL;

CREATE TABLE IF NOT EXISTS clan_members (
clan_id UUID NOT NULL REFERENCES clans(id) ON DELETE CASCADE,
character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE,
role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('leader', 'co_leader', 'member')),
joined_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (clan_id, character_id),
UNIQUE (character_id)
);

ALTER TABLE clan_members
DROP CONSTRAINT IF EXISTS clan_members_role_check;

ALTER TABLE clan_members
ADD CONSTRAINT clan_members_role_check
CHECK (role IN ('leader', 'co_leader', 'member'));

CREATE TABLE IF NOT EXISTS clan_requests (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
clan_id UUID NOT NULL REFERENCES clans(id) ON DELETE CASCADE,
character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE,
message TEXT NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (character_id)
);

CREATE INDEX IF NOT EXISTS idx_clans_leader_character_id ON clans(leader_character_id);
CREATE INDEX IF NOT EXISTS idx_characters_clan_id ON characters(clan_id);
CREATE INDEX IF NOT EXISTS idx_clan_members_clan_id ON clan_members(clan_id);
CREATE INDEX IF NOT EXISTS idx_clan_requests_clan_id ON clan_requests(clan_id);

WITH incompatible_members AS (
SELECT cm.clan_id, cm.character_id
FROM clan_members cm
Expand Down Expand Up @@ -141,39 +176,6 @@ ALTER TABLE clans
ADD CONSTRAINT clans_alignment_check
CHECK (alignment IN ('citizen', 'criminal'));

ALTER TABLE characters
ADD COLUMN IF NOT EXISTS clan_id UUID REFERENCES clans(id) ON DELETE SET NULL;

CREATE TABLE IF NOT EXISTS clan_members (
clan_id UUID NOT NULL REFERENCES clans(id) ON DELETE CASCADE,
character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE,
role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('leader', 'co_leader', 'member')),
joined_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (clan_id, character_id),
UNIQUE (character_id)
);

ALTER TABLE clan_members
DROP CONSTRAINT IF EXISTS clan_members_role_check;

ALTER TABLE clan_members
ADD CONSTRAINT clan_members_role_check
CHECK (role IN ('leader', 'co_leader', 'member'));

CREATE TABLE IF NOT EXISTS clan_requests (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
clan_id UUID NOT NULL REFERENCES clans(id) ON DELETE CASCADE,
character_id UUID NOT NULL REFERENCES characters(id) ON DELETE CASCADE,
message TEXT NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (character_id)
);

CREATE INDEX IF NOT EXISTS idx_clans_leader_character_id ON clans(leader_character_id);
CREATE INDEX IF NOT EXISTS idx_characters_clan_id ON characters(clan_id);
CREATE INDEX IF NOT EXISTS idx_clan_members_clan_id ON clan_members(clan_id);
CREATE INDEX IF NOT EXISTS idx_clan_requests_clan_id ON clan_requests(clan_id);

ALTER TABLE characters
ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ;

Expand Down
Loading