Version 1 (modified by 5 hours ago) ( diff ) | ,
---|
Напредни PostgreSQL компоненти
1) Интегритетни ограничувања (CHECK/UNIQUE) 1.1 Реакција: различни елементи
ALTER TABLE reaction ADD CONSTRAINT reaction_distinct_elements CHECK (element1_id <> element2_id);
1.2 Елементи: валидни физички вредности
ALTER TABLE elements ADD CONSTRAINT elements_atomic_number_positive CHECK (atomic_number > 0); ALTER TABLE elements ADD CONSTRAINT elements_mass_positive CHECK (atomic_weight > 0); ALTER TABLE elements ADD CONSTRAINT elements_melting_before_boiling CHECK ( boiling_point IS NULL OR melting_point IS NULL OR melting_point < boiling_point );
1.3 Партиципација: без дупликати
ALTER TABLE userparticipatesinexperiment ADD CONSTRAINT uq_user_experiment UNIQUE (user_id, experiment_id);
2) Временско печатење на учество
ALTER TABLE userparticipatesinexperiment ADD COLUMN IF NOT EXISTS participation_timestamp TIMESTAMPTZ; UPDATE userparticipatesinexperiment SET participation_timestamp = COALESCE(participation_timestamp, NOW()); ALTER TABLE userparticipatesinexperiment ALTER COLUMN participation_timestamp SET NOT NULL, ALTER COLUMN participation_timestamp SET DEFAULT NOW();
3) Тригер: set_default_safety (на experiment)
CREATE OR REPLACE FUNCTION trg_experiment_default_safety() RETURNS TRIGGER AS $$ BEGIN IF NEW.safety_warning IS NULL OR NEW.safety_warning = '' THEN NEW.safety_warning := 'Стандардни безбедносни мерки'; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; DROP TRIGGER IF EXISTS set_default_safety ON experiment; CREATE TRIGGER set_default_safety BEFORE INSERT ON experiment FOR EACH ROW EXECUTE FUNCTION trg_experiment_default_safety();
4) Погледи (Views) 4.1 vw_students_experiments_detailed
CREATE OR REPLACE VIEW vw_students_experiments_detailed AS SELECT s.student_id, (u.user_name || ' ' || u.user_surname) AS full_name, e.experiment_id, e.result, e.time_stamp AS participation_time FROM student s JOIN "User" u ON s.student_id = u.user_id JOIN userparticipatesinexperiment up ON s.student_id = up.user_id JOIN experiment e ON up.experiment_id = e.experiment_id ORDER BY u.user_name, e.time_stamp DESC;
4.2 vw_user_activity_summary
CREATE OR REPLACE VIEW vw_user_activity_summary AS SELECT u.user_id, (u.user_name || ' ' || u.user_surname) AS full_name, u.role, COUNT(DISTINCT uve.element_id) AS elements_viewed, COUNT(DISTINCT uvl.equipment_id) AS equipment_viewed, COUNT(DISTINCT upe.experiment_id) AS experiments_participated FROM "User" u LEFT JOIN userviewselement uve ON u.user_id = uve.user_id LEFT JOIN userviewslabequipment uvl ON u.user_id = uvl.user_id LEFT JOIN userparticipatesinexperiment upe ON u.user_id = upe.user_id GROUP BY u.user_id, full_name, u.role ORDER BY full_name;
4.3 vw_students_experiments_for_teacher
CREATE OR REPLACE VIEW vw_students_experiments_for_teacher AS SELECT (u.user_name || ' ' || u.user_surname) AS student_name, s.student_id, e.experiment_id, e.result, e.time_stamp, r.product, el1.symbol AS element1_symbol, el2.symbol AS element2_symbol, up.participation_timestamp AS participation_date, s.teacher_id FROM student s JOIN "User" u ON s.student_id = u.user_id JOIN userparticipatesinexperiment up ON s.student_id = up.user_id JOIN experiment e ON up.experiment_id = e.experiment_id JOIN reaction r ON e.reaction_id = r.reaction_id JOIN elements el1 ON r.element1_id = el1.element_id JOIN elements el2 ON r.element2_id = el2.element_id ORDER BY up.participation_timestamp DESC, student_name;
5) Stored function: create_reaction_and_experiment_fn(...)
create_reaction_and_experiment_fn( p_teacher_id INT, p_element1_id INT, p_element2_id INT, p_product TEXT, p_conditions TEXT, p_exp_result TEXT, p_safety TEXT, p_equipment_ids INT[] ) RETURNS TABLE(reaction_id INT, experiment_id INT)
Логика (атомично во една функција):
INSERT во reaction → reaction_id.
Ако p_exp_result е празен → авто-генерира текст „Експеримент со X + Y…“.
INSERT во experiment (time_stamp = CURRENT_TIMESTAMP, safety_warning = p_safety).
Ако има p_equipment_ids → INSERT во experimentlabequipment со unnest(p_equipment_ids).
Враќа {reaction_id, experiment_id}.
Во апликацијата, оваа функција се повикува ако е достапна; ако не, има Python fallback со транскација (исто поведение).
6) Индекси (перформанси)
CREATE INDEX IF NOT EXISTS idx_reaction_elements ON reaction (element1_id, element2_id); CREATE INDEX IF NOT EXISTS idx_exp_reaction ON experiment (reaction_id); CREATE INDEX IF NOT EXISTS idx_up_user ON userparticipatesinexperiment (user_id); CREATE INDEX IF NOT EXISTS idx_up_experiment ON userparticipatesinexperiment (experiment_id);