trading-platform-database-v2/ddl/schemas/education/functions/07-update_gamification_profile.sql
rckrdmrd 45e77e9a9c feat: Initial commit - Database schemas and scripts
DDL schemas for Trading Platform:
- User management
- Authentication
- Payments
- Education
- ML predictions
- Trading data

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 04:30:23 -06:00

159 lines
4.7 KiB
PL/PgSQL

-- =====================================================
-- FUNCTION: education.update_gamification_profile()
-- =====================================================
-- Proyecto: OrbiQuant IA (Trading Platform)
-- Módulo: OQI-002 - Education
-- Especificación: Función adicional para gamificación
-- Descripción: Actualiza el perfil de gamificación del usuario
-- =====================================================
-- Función para actualizar XP y nivel
CREATE OR REPLACE FUNCTION education.update_user_xp(
p_user_id UUID,
p_xp_to_add INTEGER
)
RETURNS VOID AS $$
DECLARE
v_profile RECORD;
v_new_total_xp INTEGER;
v_new_level INTEGER;
v_xp_to_next INTEGER;
BEGIN
-- Obtener o crear perfil
INSERT INTO education.user_gamification_profile (user_id)
VALUES (p_user_id)
ON CONFLICT (user_id) DO NOTHING;
-- Obtener perfil actual
SELECT * INTO v_profile
FROM education.user_gamification_profile
WHERE user_id = p_user_id;
-- Calcular nuevo XP total
v_new_total_xp := v_profile.total_xp + p_xp_to_add;
-- Calcular nuevo nivel (cada nivel requiere 100 XP más que el anterior)
-- Nivel 1: 0-99 XP, Nivel 2: 100-299 XP, Nivel 3: 300-599 XP, etc.
v_new_level := FLOOR((-100 + SQRT(10000 + 800 * v_new_total_xp)) / 200) + 1;
-- XP necesario para siguiente nivel
v_xp_to_next := (v_new_level * 100 + (v_new_level * (v_new_level - 1) * 100)) - v_new_total_xp;
-- Actualizar perfil
UPDATE education.user_gamification_profile
SET
total_xp = v_new_total_xp,
current_level = v_new_level,
xp_to_next_level = v_xp_to_next,
weekly_xp = weekly_xp + p_xp_to_add,
monthly_xp = monthly_xp + p_xp_to_add,
last_activity_date = CURRENT_DATE,
updated_at = NOW()
WHERE user_id = p_user_id;
-- Si subió de nivel, crear achievement
IF v_new_level > v_profile.current_level THEN
INSERT INTO education.user_achievements (
user_id,
achievement_type,
title,
description,
xp_bonus
) VALUES (
p_user_id,
'level_up',
'Level Up! - Nivel ' || v_new_level,
'Has alcanzado el nivel ' || v_new_level,
50
);
END IF;
END;
$$ LANGUAGE plpgsql;
COMMENT ON FUNCTION education.update_user_xp(UUID, INTEGER) IS 'Actualiza XP del usuario y recalcula nivel';
-- Función para actualizar streak
CREATE OR REPLACE FUNCTION education.update_user_streak(p_user_id UUID)
RETURNS VOID AS $$
DECLARE
v_last_activity DATE;
v_current_streak INTEGER;
v_longest_streak INTEGER;
BEGIN
-- Obtener o crear perfil
INSERT INTO education.user_gamification_profile (user_id)
VALUES (p_user_id)
ON CONFLICT (user_id) DO NOTHING;
-- Obtener datos actuales
SELECT last_activity_date, current_streak_days, longest_streak_days
INTO v_last_activity, v_current_streak, v_longest_streak
FROM education.user_gamification_profile
WHERE user_id = p_user_id;
-- Actualizar streak
IF v_last_activity IS NULL THEN
-- Primera actividad
v_current_streak := 1;
ELSIF v_last_activity = CURRENT_DATE THEN
-- Ya tuvo actividad hoy, no hacer nada
RETURN;
ELSIF v_last_activity = CURRENT_DATE - INTERVAL '1 day' THEN
-- Actividad día consecutivo
v_current_streak := v_current_streak + 1;
ELSE
-- Se rompió el streak
v_current_streak := 1;
END IF;
-- Actualizar longest streak si corresponde
IF v_current_streak > v_longest_streak THEN
v_longest_streak := v_current_streak;
-- Crear achievement por streak milestones
IF v_current_streak IN (7, 30, 100) THEN
INSERT INTO education.user_achievements (
user_id,
achievement_type,
title,
description,
xp_bonus,
metadata
) VALUES (
p_user_id,
'streak_milestone',
'Streak de ' || v_current_streak || ' días',
'Has mantenido una racha de ' || v_current_streak || ' días consecutivos',
v_current_streak * 5,
jsonb_build_object('streak_days', v_current_streak)
);
END IF;
END IF;
-- Actualizar perfil
UPDATE education.user_gamification_profile
SET
current_streak_days = v_current_streak,
longest_streak_days = v_longest_streak,
last_activity_date = CURRENT_DATE,
updated_at = NOW()
WHERE user_id = p_user_id;
END;
$$ LANGUAGE plpgsql;
COMMENT ON FUNCTION education.update_user_streak(UUID) IS 'Actualiza streak del usuario basado en actividad diaria';
-- Trigger para actualizar streak en actividades
CREATE OR REPLACE FUNCTION education.trigger_update_streak()
RETURNS TRIGGER AS $$
BEGIN
PERFORM education.update_user_streak(NEW.user_id);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER update_streak_on_activity
AFTER INSERT ON education.user_activity_log
FOR EACH ROW
EXECUTE FUNCTION education.trigger_update_streak();