countdown-bot

A Discord bot that runs countdown games and generates analytics
git clone https://git.ashermorgan.net/countdown-bot/
Log | Files | Refs | README

dml-core.sql (6561B)


      1 -- countdown-bot core functions and procedures
      2 
      3 DROP PROCEDURE IF EXISTS setTimezone;
      4 DROP PROCEDURE IF EXISTS getTimezone;
      5 DROP PROCEDURE IF EXISTS setReactions;
      6 DROP FUNCTION IF EXISTS getReactions;
      7 DROP PROCEDURE IF EXISTS addMessage;
      8 DROP TYPE IF EXISTS addMessageResults;
      9 DROP PROCEDURE IF EXISTS deleteCountdown;
     10 DROP PROCEDURE IF EXISTS createCountdown;
     11 DROP PROCEDURE IF EXISTS clearCountdown;
     12 DROP PROCEDURE IF EXISTS setPrefixes;
     13 DROP FUNCTION IF EXISTS getPrefixes;
     14 
     15 -- Get the active prefixes for a countdown channel
     16 CREATE FUNCTION getPrefixes (
     17     _countdownID BIGINT -- The countdown channel ID
     18 )
     19 RETURNS TABLE (
     20     prefix VARCHAR(8) -- An active prefix
     21 )
     22 LANGUAGE plpgsql AS $$
     23 BEGIN
     24     RETURN QUERY
     25     SELECT value
     26     FROM prefixes
     27     WHERE prefixes.countdownID = _countdownID;
     28 END
     29 $$;
     30 
     31 -- Set the command prefixes used by a countdown channel
     32 CREATE PROCEDURE setPrefixes (
     33     _countdownID BIGINT,   -- The countdown channel ID
     34     _prefixes VARCHAR(8)[] -- The prefix values
     35 )
     36 LANGUAGE plpgsql AS $$
     37 BEGIN
     38     DELETE FROM prefixes
     39     WHERE countdownID = _countdownID;
     40 
     41     INSERT INTO prefixes (countdownID, value)
     42     SELECT _countdownID, *
     43     FROM unnest(_prefixes);
     44 END
     45 $$;
     46 
     47 -- Delete all messages in a countdown
     48 CREATE PROCEDURE clearCountdown (
     49     _countdownID IN BIGINT -- The countdown channel ID
     50 )
     51 LANGUAGE plpgsql AS $$
     52 BEGIN
     53     DELETE
     54     FROM messages
     55     WHERE countdownID = _countdownID;
     56 END
     57 $$;
     58 
     59 -- Create a new countdown
     60 CREATE PROCEDURE createCountdown (
     61     _countdownID IN BIGINT, -- The countdown channel ID
     62     _serverID IN BIGINT,    -- The server ID
     63     prefix IN VARCHAR(8)    -- The initial prefix
     64 )
     65 LANGUAGE plpgsql AS $$
     66 BEGIN
     67     INSERT INTO countdowns (countdownID, serverID)
     68     VALUES (_countdownID, _serverID);
     69     INSERT INTO prefixes (countdownID, value)
     70     VALUES (_countdownID, prefix);
     71 END
     72 $$;
     73 
     74 -- Delete a countdown
     75 CREATE PROCEDURE deleteCountdown (
     76     _countdownID IN BIGINT -- The countdown channel ID
     77 )
     78 LANGUAGE plpgsql AS $$
     79 BEGIN
     80     DELETE
     81     FROM countdowns
     82     WHERE countdownID = _countdownID;
     83 END
     84 $$;
     85 
     86 -- Possible results of the addMessage procedure
     87 CREATE TYPE addMessageResults AS ENUM (
     88     'badCountdown', -- Countdown doesn't exist or has ended
     89     'badNumber',    -- Message number is incorrect
     90     'badUser',      -- User sent consecutive messages
     91     'good'          -- Message was successfully added
     92 );
     93 
     94 -- Validate and add a new countdown message
     95 CREATE PROCEDURE addMessage (
     96     _messageID IN BIGINT,         -- The message ID
     97     _countdownID IN BIGINT,       -- The message countdown ID
     98     _userID IN BIGINT,            -- The message user ID
     99     _value IN INT,                -- The message value
    100     _timestamp IN TIMESTAMPTZ,    -- The message timestamp
    101     result OUT addMessageResults, -- The operation result
    102     pin OUT BOOLEAN,              -- Whether the message should be pinned
    103     reactions OUT BOOLEAN         -- Whether the message has custom reactions
    104 )
    105 LANGUAGE plpgsql AS $$
    106 DECLARE
    107     lastMessage record;
    108     total INT;
    109 BEGIN
    110     -- Get last countdown message
    111     SELECT countdowns.countdownID, messageID, userID, value, timestamp
    112     INTO lastMessage
    113     FROM countdowns
    114 
    115     -- Still return a row if the countdown is empty
    116     LEFT OUTER JOIN messages
    117         ON messages.countdownID = countdowns.countdownID
    118 
    119     WHERE countdowns.countdownID = _countdownID
    120     ORDER BY messages.value ASC
    121     LIMIT 1;
    122 
    123     -- Initialize pin and reactions
    124     pin := FALSE;
    125     reactions := FALSE;
    126 
    127     -- Validate message
    128     IF lastMessage.countdownID IS NULL OR lastMessage.value = 0 THEN
    129         -- Countdown doesn't exist or has ended
    130         result := 'badCountdown';
    131 
    132     ELSEIF lastMessage.value IS NOT NULL AND
    133         lastMessage.value != _value + 1 THEN
    134         -- Message contains the wrong number
    135         result := 'badNumber';
    136 
    137     ELSEIF lastMessage.userID = _userID THEN
    138         -- User sent consecutive messages
    139         result := 'badUser';
    140 
    141     ELSE
    142         -- Message is valid, insert it into messages
    143         INSERT INTO messages (messageID, userID, countdownID, value, timestamp)
    144             VALUES (_messageID, _userID, _countdownID, _value, _timestamp);
    145         result := 'good';
    146 
    147         -- Get total from first message
    148         SELECT value
    149         INTO total
    150         FROM messages
    151         WHERE countdownID = _countdownID
    152         ORDER BY timestamp ASC
    153         LIMIT 1;
    154 
    155         -- Check if message should be pinned
    156         IF total >= 500 AND _value % (total / 50) = 0 AND _value != 0 THEN
    157             pin := TRUE;
    158         END IF;
    159 
    160         -- Check if message has custom reactions
    161         IF EXISTS(SELECT 1 FROM reactions
    162             WHERE countdownID = _countdownID AND number = _value
    163         ) THEN
    164             reactions := TRUE;
    165         END IF;
    166     END IF;
    167 END
    168 $$;
    169 
    170 -- Get the custom reactions for a number in a countdown
    171 CREATE FUNCTION getReactions (
    172     _countdownID BIGINT, -- The countdown channel ID
    173     _number INT          -- The number (or NULL for all numbers)
    174 )
    175 RETURNS TABLE (
    176     value VARCHAR(8), -- A custom reaction
    177     number INT        -- The number
    178 )
    179 LANGUAGE plpgsql AS $$
    180 BEGIN
    181     RETURN QUERY
    182     SELECT reactions.value, reactions.number
    183     FROM reactions
    184     WHERE countdownID = _countdownID
    185         AND (reactions.number = _number OR _number IS NULL)
    186     ORDER BY reactions.number DESC;
    187 END
    188 $$;
    189 
    190 -- Set the custom reactions for a number in a countdown
    191 CREATE PROCEDURE setReactions (
    192     _countdownID BIGINT,    -- The countdown channel ID
    193     _number INT,            -- The number
    194     _reactions VARCHAR(8)[] -- The custom reactions
    195 )
    196 LANGUAGE plpgsql AS $$
    197 BEGIN
    198     DELETE FROM reactions
    199     WHERE countdownID = _countdownID AND number = _number;
    200 
    201     INSERT INTO reactions (countdownID, number, value)
    202     SELECT _countdownID, _number, *
    203     FROM unnest(_reactions);
    204 END
    205 $$;
    206 
    207 -- Get the timezone of a countdown
    208 CREATE PROCEDURE getTimezone (
    209     _countdownID IN BIGINT, -- The countdown channel ID
    210     _timezone OUT FLOAT     -- The timezone as a UTC offest
    211 )
    212 LANGUAGE plpgsql AS $$
    213 BEGIN
    214     SELECT extract(hour FROM timezone) + extract(minute FROM timezone) / 60
    215     INTO _timezone
    216     FROM countdowns
    217     WHERE countdownID = _countdownID;
    218 END
    219 $$;
    220 
    221 -- Set the timezone of a countdown
    222 CREATE PROCEDURE setTimezone (
    223     _countdownID IN BIGINT, -- The countdown channel ID
    224     _timezone IN FLOAT      -- The timezone as a UTC offest
    225 )
    226 LANGUAGE plpgsql AS $$
    227 BEGIN
    228     UPDATE countdowns
    229     SET timezone = make_interval(mins => (_timezone * 60)::integer)
    230     WHERE countdownID = _countdownID;
    231 END
    232 $$;