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 $$;