DROP TRIGGER IF EXISTS constraint_eye_deleted_object_has_no_actual_relation ON eye.object;

DROP FUNCTION IF EXISTS check_eye_object_has_no_relation();

CREATE OR REPLACE FUNCTION check_eye_deleted_object_has_no_relation() RETURNS TRIGGER AS $$
DECLARE
    relation_id int;
    deleted boolean;
BEGIN
    SELECT object.deleted INTO deleted
        FROM eye.object as object
        WHERE object.object_id = NEW.object_id;

    IF NOT FOUND THEN
        RAISE EXCEPTION 'Object % had been deleted', NEW.object_id
            USING ERRCODE = 'integrity_constraint_violation';
    END IF;

    IF NOT deleted THEN
        RETURN NEW;
    END IF;

    SELECT relation.relation_id INTO relation_id 
        FROM eye.primary_detection_relation AS relation
        WHERE relation.primary_detection_id = NEW.primary_detection_id AND NOT relation.deleted
        LIMIT 1;

    IF FOUND THEN
        RAISE EXCEPTION 'Object % has relation %!', NEW.object_id, relation_id
            USING ERRCODE = 'integrity_constraint_violation';
    END IF;

    RETURN NEW;
END;
$$ language plpgsql;

-- Attention! Triggers fires at the end of transaction.
-- In case of object deletion it's needed to verify that there is no any actual relations.
CREATE CONSTRAINT TRIGGER constraint_eye_deleted_object_has_no_actual_relation
    AFTER INSERT OR UPDATE ON eye.object
    DEFERRABLE INITIALLY DEFERRED 
    FOR EACH ROW
    WHEN (NEW.deleted)
    EXECUTE PROCEDURE check_eye_deleted_object_has_no_relation();


CREATE OR REPLACE FUNCTION check_eye_relation_and_object_consistency() RETURNS TRIGGER AS $$
DECLARE
    obj RECORD;
    deleted boolean;
BEGIN
    SELECT * INTO obj
        FROM eye.object
        WHERE  primary_detection_id = NEW.primary_detection_id;

    IF NOT FOUND THEN
        RAISE EXCEPTION 'No object for relation %!', NEW.relation_id
            USING ERRCODE = 'integrity_constraint_violation';
    END IF;

    SELECT relation.deleted INTO deleted
        FROM eye.primary_detection_relation as relation
        WHERE relation.relation_id = NEW.relation_id;

    IF NOT FOUND THEN
        RAISE EXCEPTION 'Relation % had been deleted', NEW.relation_id
            USING ERRCODE = 'integrity_constraint_violation';
    END IF;

    IF NOT deleted AND obj.deleted THEN
        RAISE EXCEPTION 'Relation % for deleted object %!', NEW.relation_id, obj.object_id
            USING ERRCODE = 'integrity_constraint_violation';
    END IF;

    RETURN NEW;
END;
$$ language plpgsql;


DROP TRIGGER IF EXISTS constraint_eye_relation_and_object_consistency ON eye.primary_detection_relation;

-- Attention! Triggers fires at the end of transaction.
-- In case of relation creation or update it's needed to verify object state.
CREATE CONSTRAINT TRIGGER constraint_eye_relation_and_object_consistency
    AFTER INSERT OR UPDATE ON eye.primary_detection_relation
    DEFERRABLE INITIALLY DEFERRED 
    FOR EACH ROW
    EXECUTE PROCEDURE check_eye_relation_and_object_consistency();
