-- Экономика: баланс, опыт, очищение, яички. -- 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; $$;