36 lines
1.5 KiB
SQL
36 lines
1.5 KiB
SQL
CREATE TABLE guild_members (
|
|
guild_id BYTEA NOT NULL CHECK(length(guild_id) = 26),
|
|
user_id BYTEA NOT NULL CHECK(length(user_id) = 26),
|
|
|
|
-- Core identity
|
|
nick TEXT CHECK (LENGTH(COALESCE(nick, '')) <= 32), -- display name in guild (NULL = uses user global name)
|
|
joined_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
-- Roles & permissions
|
|
roles BYTEA[] NOT NULL DEFAULT ARRAY[]::BYTEA[], -- array of role IDs (26-byte each)
|
|
boosting_since TIMESTAMPTZ, -- when they started boosting (NULL = not boosting)
|
|
|
|
-- Voice state (lightweight caching)
|
|
voice_channel_id BYTEA CHECK(length(voice_channel_id) = 26),
|
|
deafened BOOLEAN NOT NULL DEFAULT FALSE,
|
|
muted BOOLEAN NOT NULL DEFAULT FALSE,
|
|
|
|
-- Moderation & management
|
|
pending BOOLEAN NOT NULL DEFAULT FALSE, -- requires membership screening
|
|
timed_out_until TIMESTAMPTZ, -- NULL = not timed out
|
|
|
|
-- Audit & integrity
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
|
|
-- Composite primary key
|
|
PRIMARY KEY (guild_id, user_id)
|
|
);
|
|
|
|
-- Critical indexes
|
|
CREATE INDEX idx_guild_members_user_id ON guild_members (user_id);
|
|
CREATE INDEX idx_guild_members_guild_id ON guild_members (guild_id);
|
|
CREATE INDEX idx_guild_members_roles ON guild_members USING GIN (roles); -- for role-based lookups
|
|
CREATE INDEX idx_guild_members_voice_channel_id ON guild_members (voice_channel_id) WHERE voice_channel_id IS NOT NULL;
|
|
|
|
-- For quick "all members in guild" queries (covering index)
|
|
CREATE INDEX idx_guild_members_guild_id_nick ON guild_members (guild_id, nick); |