Cambios Grandes, editro nuevo de preguntas, logica nueva con mas opciones de pregutnas con preguntas hijos hasta 5 niveles
This commit is contained in:
172
migrations/add_nested_subquestions.sql
Normal file
172
migrations/add_nested_subquestions.sql
Normal file
@@ -0,0 +1,172 @@
|
||||
-- Migración: Subpreguntas anidadas hasta 5 niveles
|
||||
-- Fecha: 2025-11-25
|
||||
-- Descripción: Agrega soporte y validación para subpreguntas anidadas hasta 5 niveles de profundidad
|
||||
|
||||
-- Agregar columna para tracking de nivel (opcional pero útil)
|
||||
ALTER TABLE questions
|
||||
ADD COLUMN IF NOT EXISTS depth_level INTEGER DEFAULT 0;
|
||||
|
||||
-- Comentarios
|
||||
COMMENT ON COLUMN questions.parent_question_id IS 'ID de la pregunta padre. NULL = pregunta principal. Soporta anidamiento hasta 5 niveles.';
|
||||
COMMENT ON COLUMN questions.depth_level IS 'Nivel de profundidad: 0=principal, 1-5=subpreguntas anidadas';
|
||||
|
||||
-- Función para calcular profundidad de una pregunta
|
||||
CREATE OR REPLACE FUNCTION calculate_question_depth(question_id INTEGER)
|
||||
RETURNS INTEGER AS $$
|
||||
DECLARE
|
||||
current_parent_id INTEGER;
|
||||
depth INTEGER := 0;
|
||||
max_iterations INTEGER := 10; -- Protección contra loops infinitos
|
||||
BEGIN
|
||||
-- Obtener el parent_id de la pregunta
|
||||
SELECT parent_question_id INTO current_parent_id
|
||||
FROM questions
|
||||
WHERE id = question_id;
|
||||
|
||||
-- Si no tiene padre, es nivel 0
|
||||
IF current_parent_id IS NULL THEN
|
||||
RETURN 0;
|
||||
END IF;
|
||||
|
||||
-- Subir por la jerarquía contando niveles
|
||||
WHILE current_parent_id IS NOT NULL AND depth < max_iterations LOOP
|
||||
depth := depth + 1;
|
||||
|
||||
SELECT parent_question_id INTO current_parent_id
|
||||
FROM questions
|
||||
WHERE id = current_parent_id;
|
||||
END LOOP;
|
||||
|
||||
RETURN depth;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Función trigger para validar profundidad máxima
|
||||
CREATE OR REPLACE FUNCTION validate_question_depth()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
calculated_depth INTEGER;
|
||||
parent_depth INTEGER;
|
||||
BEGIN
|
||||
-- Si no tiene padre, es nivel 0
|
||||
IF NEW.parent_question_id IS NULL THEN
|
||||
NEW.depth_level := 0;
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
-- Validar que el padre existe y no es la misma pregunta
|
||||
IF NEW.parent_question_id = NEW.id THEN
|
||||
RAISE EXCEPTION 'Una pregunta no puede ser su propio padre';
|
||||
END IF;
|
||||
|
||||
-- Calcular profundidad del padre
|
||||
SELECT depth_level INTO parent_depth
|
||||
FROM questions
|
||||
WHERE id = NEW.parent_question_id;
|
||||
|
||||
IF parent_depth IS NULL THEN
|
||||
-- Si el padre no tiene depth_level, calcularlo
|
||||
parent_depth := calculate_question_depth(NEW.parent_question_id);
|
||||
END IF;
|
||||
|
||||
-- La nueva pregunta es un nivel más profundo que su padre
|
||||
calculated_depth := parent_depth + 1;
|
||||
|
||||
-- Validar que no excede 5 niveles
|
||||
IF calculated_depth > 5 THEN
|
||||
RAISE EXCEPTION 'No se permiten subpreguntas con profundidad mayor a 5. Esta pregunta tendría profundidad %, máximo permitido: 5', calculated_depth;
|
||||
END IF;
|
||||
|
||||
-- Asignar el nivel calculado
|
||||
NEW.depth_level := calculated_depth;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Crear trigger para INSERT y UPDATE
|
||||
DROP TRIGGER IF EXISTS validate_depth_trigger ON questions;
|
||||
CREATE TRIGGER validate_depth_trigger
|
||||
BEFORE INSERT OR UPDATE OF parent_question_id ON questions
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION validate_question_depth();
|
||||
|
||||
-- Actualizar depth_level para preguntas existentes
|
||||
UPDATE questions
|
||||
SET depth_level = calculate_question_depth(id);
|
||||
|
||||
-- Crear índice para mejorar queries de subpreguntas
|
||||
CREATE INDEX IF NOT EXISTS idx_questions_parent ON questions(parent_question_id) WHERE parent_question_id IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_questions_depth ON questions(depth_level);
|
||||
|
||||
-- Función helper para obtener árbol de subpreguntas
|
||||
CREATE OR REPLACE FUNCTION get_question_tree(root_question_id INTEGER)
|
||||
RETURNS TABLE (
|
||||
id INTEGER,
|
||||
parent_question_id INTEGER,
|
||||
text TEXT,
|
||||
type VARCHAR(30),
|
||||
depth_level INTEGER,
|
||||
show_if_answer VARCHAR(50),
|
||||
path TEXT
|
||||
) AS $$
|
||||
BEGIN
|
||||
RETURN QUERY
|
||||
WITH RECURSIVE question_tree AS (
|
||||
-- Pregunta raíz
|
||||
SELECT
|
||||
q.id,
|
||||
q.parent_question_id,
|
||||
q.text,
|
||||
q.type,
|
||||
q.depth_level,
|
||||
q.show_if_answer,
|
||||
q.id::TEXT as path
|
||||
FROM questions q
|
||||
WHERE q.id = root_question_id
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Subpreguntas recursivas
|
||||
SELECT
|
||||
q.id,
|
||||
q.parent_question_id,
|
||||
q.text,
|
||||
q.type,
|
||||
q.depth_level,
|
||||
q.show_if_answer,
|
||||
qt.path || ' > ' || q.id::TEXT
|
||||
FROM questions q
|
||||
INNER JOIN question_tree qt ON q.parent_question_id = qt.id
|
||||
WHERE q.depth_level <= 5 -- Límite de seguridad
|
||||
)
|
||||
SELECT * FROM question_tree
|
||||
ORDER BY depth_level, id;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
-- Verificar estructura actual
|
||||
SELECT
|
||||
COUNT(*) as total_preguntas,
|
||||
COUNT(CASE WHEN parent_question_id IS NULL THEN 1 END) as principales,
|
||||
COUNT(CASE WHEN parent_question_id IS NOT NULL THEN 1 END) as subpreguntas,
|
||||
MAX(depth_level) as max_profundidad
|
||||
FROM questions;
|
||||
|
||||
-- Ver distribución por profundidad
|
||||
SELECT
|
||||
depth_level,
|
||||
COUNT(*) as cantidad,
|
||||
CASE
|
||||
WHEN depth_level = 0 THEN 'Principales'
|
||||
WHEN depth_level = 1 THEN 'Nivel 1'
|
||||
WHEN depth_level = 2 THEN 'Nivel 2'
|
||||
WHEN depth_level = 3 THEN 'Nivel 3'
|
||||
WHEN depth_level = 4 THEN 'Nivel 4'
|
||||
WHEN depth_level = 5 THEN 'Nivel 5'
|
||||
END as descripcion
|
||||
FROM questions
|
||||
GROUP BY depth_level
|
||||
ORDER BY depth_level;
|
||||
|
||||
SELECT '✓ Migración de subpreguntas anidadas completada' AS status;
|
||||
Reference in New Issue
Block a user