143 lines
5.1 KiB
SQL
143 lines
5.1 KiB
SQL
-- PostgreSQL-oriented schema for Rolemaster critical tables.
|
|
-- It is intentionally hybrid: relational axes + raw text + parsed JSON.
|
|
|
|
create table critical_table (
|
|
id bigint generated always as identity primary key,
|
|
slug text not null unique,
|
|
display_name text not null,
|
|
family text not null check (family in ('standard', 'variant_column', 'grouped_variant')),
|
|
source_pdf text not null,
|
|
source_page integer not null default 1,
|
|
extraction_method text not null check (extraction_method in ('text', 'ocr', 'manual')),
|
|
notes text,
|
|
created_at timestamptz not null default now()
|
|
);
|
|
|
|
create table critical_group (
|
|
id bigint generated always as identity primary key,
|
|
critical_table_id bigint not null references critical_table(id) on delete cascade,
|
|
group_key text not null,
|
|
label text not null,
|
|
sort_order integer not null,
|
|
unique (critical_table_id, group_key)
|
|
);
|
|
|
|
create table critical_column (
|
|
id bigint generated always as identity primary key,
|
|
critical_table_id bigint not null references critical_table(id) on delete cascade,
|
|
column_key text not null,
|
|
label text not null,
|
|
role text not null default 'severity' check (role in ('severity', 'variant', 'other')),
|
|
sort_order integer not null,
|
|
unique (critical_table_id, column_key)
|
|
);
|
|
|
|
create table critical_roll_band (
|
|
id bigint generated always as identity primary key,
|
|
critical_table_id bigint not null references critical_table(id) on delete cascade,
|
|
label text not null,
|
|
min_roll integer not null,
|
|
max_roll integer,
|
|
sort_order integer not null,
|
|
check (max_roll is null or max_roll >= min_roll),
|
|
unique (critical_table_id, label)
|
|
);
|
|
|
|
create index critical_roll_band_lookup_idx
|
|
on critical_roll_band (critical_table_id, min_roll, max_roll);
|
|
|
|
create table critical_result (
|
|
id bigint generated always as identity primary key,
|
|
critical_table_id bigint not null references critical_table(id) on delete cascade,
|
|
critical_group_id bigint references critical_group(id) on delete cascade,
|
|
critical_column_id bigint not null references critical_column(id) on delete cascade,
|
|
critical_roll_band_id bigint not null references critical_roll_band(id) on delete cascade,
|
|
raw_cell_text text not null,
|
|
description_text text,
|
|
raw_affix_text text,
|
|
parsed_json jsonb not null default '{}'::jsonb,
|
|
parse_status text not null default 'raw' check (parse_status in ('raw', 'partial', 'parsed', 'verified')),
|
|
source_bbox jsonb,
|
|
created_at timestamptz not null default now()
|
|
);
|
|
|
|
create unique index critical_result_lookup_uidx
|
|
on critical_result (
|
|
critical_table_id,
|
|
coalesce(critical_group_id, 0),
|
|
critical_column_id,
|
|
critical_roll_band_id
|
|
);
|
|
|
|
create table critical_branch (
|
|
id bigint generated always as identity primary key,
|
|
critical_result_id bigint not null references critical_result(id) on delete cascade,
|
|
branch_kind text not null default 'conditional' check (branch_kind in ('conditional', 'note', 'override')),
|
|
condition_key text,
|
|
condition_text text not null,
|
|
condition_json jsonb not null default '{}'::jsonb,
|
|
raw_text text not null,
|
|
description_text text,
|
|
raw_affix_text text,
|
|
parsed_json jsonb not null default '{}'::jsonb,
|
|
sort_order integer not null default 1
|
|
);
|
|
|
|
create table critical_effect (
|
|
id bigint generated always as identity primary key,
|
|
critical_result_id bigint references critical_result(id) on delete cascade,
|
|
critical_branch_id bigint references critical_branch(id) on delete cascade,
|
|
effect_code text not null,
|
|
target text,
|
|
value_integer integer,
|
|
value_decimal numeric(10, 2),
|
|
duration_rounds integer,
|
|
per_round integer,
|
|
modifier integer,
|
|
body_part text,
|
|
is_permanent boolean not null default false,
|
|
source_type text not null default 'symbol' check (source_type in ('symbol', 'prose', 'manual')),
|
|
source_text text,
|
|
check ((critical_result_id is not null) <> (critical_branch_id is not null))
|
|
);
|
|
|
|
create index critical_effect_lookup_idx
|
|
on critical_effect (effect_code, target);
|
|
|
|
create index critical_effect_result_idx
|
|
on critical_effect (critical_result_id);
|
|
|
|
create index critical_effect_branch_idx
|
|
on critical_effect (critical_branch_id);
|
|
|
|
create index critical_result_parsed_json_gin
|
|
on critical_result using gin (parsed_json);
|
|
|
|
create index critical_branch_parsed_json_gin
|
|
on critical_branch using gin (parsed_json);
|
|
|
|
-- Example lookup pattern:
|
|
--
|
|
-- select
|
|
-- t.slug as critical_type,
|
|
-- t.display_name as table_name,
|
|
-- g.group_key,
|
|
-- c.column_key,
|
|
-- rb.label as roll_band,
|
|
-- rb.min_roll,
|
|
-- rb.max_roll,
|
|
-- r.description_text,
|
|
-- r.raw_affix_text,
|
|
-- r.raw_cell_text,
|
|
-- r.parsed_json
|
|
-- from critical_result r
|
|
-- join critical_table t on t.id = r.critical_table_id
|
|
-- left join critical_group g on g.id = r.critical_group_id
|
|
-- join critical_column c on c.id = r.critical_column_id
|
|
-- join critical_roll_band rb on rb.id = r.critical_roll_band_id
|
|
-- where t.slug = 'slash'
|
|
-- and c.column_key = 'C'
|
|
-- and 38 >= rb.min_roll
|
|
-- and (rb.max_roll is null or 38 <= rb.max_roll);
|
|
|