Pular para conteúdo

Triggers e Procedures

Introdução

Triggers e stored procedures são componentes importantes em bancos de dados relacionais, como o MySQL, SQL Server, PostgreSQL, entre outros. Eles desempenham papéis distintos, mas ambos são utilizados para automação de tarefas e execução de lógica no banco de dados.

Triggers e Procedures

Abaixo, veja o código das triggers e procedures criadas para o nosso jogo:


-- Trigger para atualizar automaticamente o status da missão:

CREATE OR REPLACE FUNCTION atualiza_status_missao()
RETURNS TRIGGER AS $$
DECLARE
    total_etapas INT;
    etapas_concluidas INT;
BEGIN
    SELECT COUNT(*) INTO total_etapas
    FROM EtapaMissao
    WHERE Missao = NEW.Missao;

    SELECT COUNT(*) INTO etapas_concluidas
    FROM EtapaMissao em
    JOIN RealizaMissao rm ON em.IdEtapaMissao = rm.Missao
    WHERE em.Missao = NEW.Missao AND em.Status = 1;

    IF total_etapas = etapas_concluidas THEN
        UPDATE Missao
        SET Status = 1
        WHERE IdMissao = NEW.Missao;
    END IF;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trigger_atualiza_status_missao
AFTER UPDATE ON EtapaMissao
FOR EACH ROW
EXECUTE FUNCTION atualiza_status_missao();

-- Trigger para realizar a compra de um item por um jogador

CREATE OR REPLACE FUNCTION realizar_compra(
    jogador_id INT,
    item_id INT,
    quantidade INT
) RETURNS VOID AS $$
DECLARE
    custo_total INT;
BEGIN
    SELECT (CustoCompra * quantidade)
    INTO custo_total
    FROM Item
    WHERE IdItem = item_id;

    IF (SELECT Dinheiro FROM PC WHERE IdPlayer = jogador_id) >= custo_total THEN
        INSERT INTO Inventario (PC, CapacidadeMaxima)
        VALUES (jogador_id, 20)
        ON CONFLICT (PC) DO NOTHING;

        INSERT INTO InventarioItem (Inventario, Item, Quantidade)
        VALUES (jogador_id, item_id, quantidade)
        ON CONFLICT (Inventario, Item) DO UPDATE
        SET Quantidade = InventarioItem.Quantidade + quantidade;

        UPDATE PC
        SET Dinheiro = Dinheiro - custo_total
        WHERE IdPlayer = jogador_id;

        RAISE NOTICE 'Compra realizada com sucesso!';
    ELSE
        RAISE EXCEPTION 'Dinheiro insuficiente para realizar a compra!';
    END IF;
END;
$$ LANGUAGE plpgsql;
EXECUTE FUNCTION criar_amigato_para_pc();

-- Trigger para evolução de Amigato:

CREATE OR REPLACE FUNCTION evolui_amigato()
RETURNS TRIGGER AS $$
BEGIN
    UPDATE Amigato
    SET Nivel = Nivel + 1
    WHERE IdAmigato = NEW.Amigato AND NEW.Status = 1;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trig_evolui_amigato
AFTER INSERT ON AtacaMonstro
FOR EACH ROW
EXECUTE FUNCTION evolui_amigato();

-- Trigger para Recompensa Automática ao Vencer uma Missão:

CREATE OR REPLACE FUNCTION recompensa_missao()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO GuardaItem (Inventario, Item)
    SELECT NEW.PC, Item
    FROM Missao
        JOIN DropaItem ON Missao.IdMissao = DropaItem.Missao
    WHERE NEW.Missao = Missao.IdMissao;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trig_recompensa_missao
AFTER UPDATE ON RealizaMissao
FOR EACH ROW
WHEN (NEW.Status = 1)
EXECUTE FUNCTION recompensa_missao();

-- Trigger para atualizar status do amigato após uma missão bem-sucedida:

CREATE OR REPLACE FUNCTION atualiza_status_amigato()
RETURNS TRIGGER AS $$
BEGIN
    UPDATE Amigato
    SET Status = 1
    WHERE IdAmigato = NEW.Amigato AND NEW.Status = 1;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trig_atualiza_status_amigato
AFTER UPDATE ON RealizaMissao
FOR EACH ROW
WHEN (NEW.Status = 1)
EXECUTE FUNCTION atualiza_status_amigato();

-- Procedure para atualizar o status da missão:

CREATE OR REPLACE FUNCTION atualizar_status_missao(
    p_missao_id INT,
    p_novo_status INT
)
RETURNS VOID AS $$
BEGIN
    UPDATE Missao
    SET Status = p_novo_status
    WHERE IdMissao = p_missao_id;
    RAISE NOTICE 'Status da missão atualizado com sucesso!';
END;
$$ LANGUAGE plpgsql;

-- Procedure para conclusão de uma etapa da missão:

CREATE OR REPLACE FUNCTION concluir_etapa_missao(
    p_etapa_id INT
)
RETURNS VOID AS $$
BEGIN
    UPDATE EtapaMissao
    SET Status = 1
    WHERE IdEtapaMissao = p_etapa_id;
    RAISE NOTICE 'Etapa de missão concluída com sucesso!';
END;
$$ LANGUAGE plpgsql;

-- Procedure para Trocar de Armadura:

CREATE OR REPLACE FUNCTION trocar_armadura(
    p_player_id INT,
    p_nova_armadura_id INT
)
RETURNS VOID AS $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM Armadura WHERE IdArmadura = p_nova_armadura_id) THEN
        RAISE EXCEPTION 'Armadura não encontrada!';
    END IF;

    UPDATE PC
    SET Armadura = p_nova_armadura_id
    WHERE IdPlayer = p_player_id;

    RAISE NOTICE 'Armadura trocada com sucesso!';
END;
$$ LANGUAGE plpgsql;

-- Procedure para Comprar Item na Loja:

CREATE OR REPLACE FUNCTION comprar_item_na_loja(
    p_player_id INT,
    p_loja_id INT,
    p_item_id INT,
    p_quantidade INT
)
RETURNS VOID AS $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM PC WHERE IdPlayer = p_player_id) THEN
        RAISE EXCEPTION 'Jogador não encontrado!';
    END IF;

    IF NOT EXISTS (SELECT 1 FROM Loja WHERE IdLoja = p_loja_id) THEN
        RAISE EXCEPTION 'Loja não encontrada!';
    END IF;

    IF NOT EXISTS (
        SELECT 1
        FROM VendeItem
        WHERE Loja = p_loja_id
          AND Item = p_item_id
    ) THEN
        RAISE EXCEPTION 'Item não disponível nesta loja!';
    END IF;

    DECLARE custo_total INT;
    SELECT CustoCompra * p_quantidade INTO custo_total
    FROM Item
    WHERE IdItem = p_item_id;

    IF NOT EXISTS (
        SELECT 1
        FROM PC
        WHERE IdPlayer = p_player_id
          AND Dinheiro >= custo_total
    ) THEN
        RAISE EXCEPTION 'Dinheiro insuficiente para comprar o item!';
    END IF;

    INSERT INTO InventarioItem (Inventario, Item, Quantidade)
    VALUES (p_player_id, p_item_id, p_quantidade)
    ON CONFLICT (Inventario, Item) DO UPDATE
    SET Quantidade = InventarioItem.Quantidade + p_quantidade;

    UPDATE PC
    SET Dinheiro = Dinheiro - custo_total
    WHERE IdPlayer = p_player_id;

    RAISE NOTICE 'Compra realizada com sucesso!';
END;
$$ LANGUAGE plpgsql;

-- Procedure para Criar Nova Arma na Forja:

CREATE OR REPLACE FUNCTION criar_nova_arma_na_forja(
    p_forja_id INT,
    p_tipo_arma INT,
    p_nome VARCHAR(64),
    p_nivel INT,
    p_raridade INT,
    p_custo_compra INT,
    p_valor_venda INT,
    p_descricao VARCHAR(256),
    p_ataque INT,
    p_afiacao INT,
    p_elemento VARCHAR(32),
    p_valor_elemento INT
)
RETURNS VOID AS $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM Forja WHERE IdForja = p_forja_id) THEN
        RAISE EXCEPTION 'Forja não encontrada!';
    END IF;

    INSERT INTO Equipamento (Categoria)
    VALUES (1)
    RETURNING IdEquipamento INTO p_nova_arma_id;

    INSERT INTO Arma (
        IdArma, Nome, Nivel, Raridade, CustoCompra,
        ValorVenda, Descricao, Tipo, Ataque, Afiacao,
        Elemento, ValorElemento
    )
    VALUES (
        p_nova_arma_id, p_nome, p_nivel, p_raridade, p_custo_compra,
        p_valor_venda, p_descricao, p_tipo_arma, p_ataque, p_afiacao,
        p_elemento, p_valor_elemento
    );

    INSERT INTO CriaEquipamento (Forja, Equipamento)
    VALUES (p_forja_id, p_nova_arma_id);

    RAISE NOTICE 'Nova arma criada na forja com sucesso!';
END;
$$ LANGUAGE plpgsql;

-- Procedure para Adicionar Item ao Inventario de um Jogador:

CREATE OR REPLACE FUNCTION adicionar_item_ao_inventario(
    p_player_id INT,
    p_item_id INT,
    p_quantidade INT
)
RETURNS VOID AS $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM PC WHERE IdPlayer = p_player_id) THEN
        RAISE EXCEPTION 'Jogador não encontrado!';
    END IF;

    IF NOT EXISTS (SELECT 1 FROM Item WHERE IdItem = p_item_id) THEN
        RAISE EXCEPTION 'Item não encontrado!';
    END IF;

    INSERT INTO InventarioItem (Inventario, Item, Quantidade)
    VALUES (p_player_id, p_item_id, p_quantidade)
    ON CONFLICT (Inventario, Item) DO UPDATE
    SET Quantidade = InventarioItem.Quantidade + p_quantidade;

    RAISE NOTICE 'Item adicionado ao inventário com sucesso!';
END;
$$ LANGUAGE plpgsql;

-- Procedure para Compra de Item:

CREATE OR REPLACE FUNCTION comprar_item_na_loja(
    p_player_id INT,
    p_loja_id INT,
    p_item_id INT,
    p_quantidade INT
)
RETURNS VOID AS $$
BEGIN
    IF NOT EXISTS (SELECT 1 FROM PC WHERE IdPlayer = p_player_id) THEN
        RAISE EXCEPTION 'Jogador não encontrado!';
    END IF;

    IF NOT EXISTS (SELECT 1 FROM Loja WHERE IdLoja = p_loja_id) THEN
        RAISE EXCEPTION 'Loja não encontrada!';
    END IF;

    IF NOT EXISTS (
        SELECT 1
        FROM VendeItem
        WHERE Loja = p_loja_id
          AND Item = p_item_id
    ) THEN
        RAISE EXCEPTION 'Item não disponível nesta loja!';
    END IF;

    DECLARE custo_total INT;
    SELECT CustoCompra * p_quantidade INTO custo_total
    FROM Item
    WHERE IdItem = p_item_id;

    IF NOT EXISTS (
        SELECT 1
        FROM PC
        WHERE IdPlayer = p_player_id
          AND Dinheiro >= custo_total
    ) THEN
        RAISE EXCEPTION 'Dinheiro insuficiente para comprar o item!';
    END IF;

    INSERT INTO InventarioItem (Inventario, Item, Quantidade)
    VALUES (p_player_id, p_item_id, p_quantidade)
    ON CONFLICT (Inventario, Item) DO UPDATE
    SET Quantidade = InventarioItem.Quantidade + p_quantidade;

    UPDATE PC
    SET Dinheiro = Dinheiro - custo_total
    WHERE IdPlayer = p_player_id;

    RAISE NOTICE 'Compra realizada com sucesso!';
END;
$$ LANGUAGE plpgsql;