DispelEvilBot/sql/R__functions_economy.sql

187 lines
4.7 KiB
PL/PgSQL

-- Экономика: баланс, опыт, очищение, яички.
-- Repeatable-миграция: перезапускается при изменении (CREATE OR REPLACE).
CREATE OR REPLACE FUNCTION bot.get_money(p_id_user bigint) RETURNS bigint
LANGUAGE plpgsql
AS $$
DECLARE
v_money bigint;
BEGIN
SELECT sum(amount) INTO v_money FROM bot.money WHERE id_user = p_id_user;
RETURN v_money;
END;
$$;
CREATE OR REPLACE FUNCTION bot.get_eggs(p_id_user bigint) RETURNS bigint
LANGUAGE plpgsql
AS $$
DECLARE
v_result bigint;
BEGIN
SELECT sum(amount) INTO v_result FROM bot.eggs WHERE id_user = p_id_user;
RETURN v_result;
END;
$$;
CREATE OR REPLACE PROCEDURE bot.money_action(
IN p_id_user bigint,
IN p_money bigint,
IN p_id_action bigint DEFAULT 1
) LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO bot.money (id_user, amount, id_action)
VALUES (p_id_user, p_money, p_id_action);
END;
$$;
-- Ежедневное очищение: опыт, монеты, уровень.
-- Колонки lvl_before/lvl/streak нужны аналитике (события exp_accrual и level_up),
-- поэтому сигнатуру пришлось изменить — сначала DROP (repeatable-миграция).
DROP FUNCTION IF EXISTS bot.purification(bigint);
CREATE OR REPLACE FUNCTION bot.purification(p_id_user bigint)
RETURNS TABLE(
res integer,
expr_add bigint,
mny_add bigint,
h integer,
m integer,
s integer,
lvl_before bigint,
lvl_after bigint,
streak bigint
)
LANGUAGE plpgsql
AS $$
DECLARE
v_lvl bigint;
v_lvl_before bigint;
v_expr bigint;
v_expr_add bigint;
v_streak bigint;
v_mny_add bigint;
v_dt_pur timestamp;
v_days bigint;
v_result integer;
v_h integer;
v_m integer;
v_s integer;
BEGIN
SELECT lvl, expr, expr_streak
INTO v_lvl, v_expr, v_streak
FROM bot.de_users
WHERE id_user = p_id_user;
v_lvl_before := v_lvl;
BEGIN
SELECT dt INTO v_dt_pur
FROM (
SELECT dt, row_number() OVER (ORDER BY dt DESC) rn
FROM bot.purifications
WHERE id_user = p_id_user
) t
WHERE rn = 1;
EXCEPTION
WHEN others THEN
v_dt_pur := null;
END;
IF v_dt_pur IS NULL THEN
v_days := -1;
ELSE
v_days = extract(day FROM now() - v_dt_pur);
END IF;
IF v_days = 0 THEN
v_result := 0;
v_h := 23 - extract(hour FROM now() - v_dt_pur);
v_m := 59 - extract(minute FROM now() - v_dt_pur);
v_s := 59 - extract(sec FROM now() - v_dt_pur);
ELSE
v_mny_add := floor(random() * 21) + 30;
v_expr_add := 1;
IF v_days = 1 THEN
IF v_streak < 30 THEN
v_streak := v_streak + 1;
END IF;
v_expr_add := v_expr_add + v_streak;
ELSE
v_streak := 0;
END IF;
v_expr := v_expr + v_expr_add;
WHILE v_expr >= v_lvl * 10 LOOP
v_expr := v_expr - v_lvl * 10;
v_lvl := v_lvl + 1;
END LOOP;
UPDATE bot.de_users
SET lvl = v_lvl, expr = v_expr, expr_streak = v_streak
WHERE id_user = p_id_user;
INSERT INTO bot.money (id_user, amount, id_action)
VALUES (p_id_user, v_mny_add, 4);
INSERT INTO bot.purifications (id_user) VALUES (p_id_user);
v_result := 1;
END IF;
RETURN QUERY SELECT v_result, v_expr_add, v_mny_add, v_h, v_m, v_s, v_lvl_before, v_lvl, v_streak;
END;
$$;
CREATE OR REPLACE FUNCTION bot.add_eggs(p_id_user bigint)
RETURNS TABLE(res integer, eggs_add bigint, h integer, m integer, s integer)
LANGUAGE plpgsql
AS $$
DECLARE
v_dt timestamp;
v_egg_add bigint;
v_days bigint;
v_h integer;
v_m integer;
v_s integer;
v_result integer;
BEGIN
BEGIN
SELECT dt_action INTO v_dt
FROM (
SELECT dt_action, row_number() OVER (ORDER BY dt_action DESC) rn
FROM bot.eggs
WHERE id_user = p_id_user AND id_action = 1
) t
WHERE rn = 1;
EXCEPTION
WHEN others THEN
v_dt := null;
END;
IF v_dt IS NULL THEN
v_days := -1;
ELSE
v_days = extract(day FROM now() - v_dt);
END IF;
IF v_days = 0 THEN
v_result := 0;
v_h := 23 - extract(hour FROM now() - v_dt);
v_m := 59 - extract(minute FROM now() - v_dt);
v_s := 59 - extract(sec FROM now() - v_dt);
ELSE
v_egg_add := floor(random() * 31) + 10;
INSERT INTO bot.eggs (id_user, id_action, amount)
VALUES (p_id_user, 1, v_egg_add);
v_result := 1;
END IF;
RETURN QUERY SELECT v_result, v_egg_add, v_h, v_m, v_s;
END;
$$;