// Copyright 2022 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source // License, and you may not use this file except in compliance with the Business Source License. // // As of the Change Date specified in that file, in accordance with // the Business Source License, use of this software will be governed // by the Apache License, Version 2.0, included in the file // licenses/APL.txt. #include #include #include #include #include "common.hpp" #include "utils/logging.hpp" inline constexpr std::string_view kTriggerCreatedVertexLabel{"CREATED_VERTEX"}; inline constexpr std::string_view kTriggerCreatedEdgeLabel{"CREATED_EDGE"}; inline constexpr std::string_view kTriggerCreatedObjectLabel{"CREATED_OBJECT"}; void CreateOnCreateTriggers(mg::Client &client, bool is_before) { const std::string_view before_or_after = is_before ? "BEFORE" : "AFTER"; client.Execute( fmt::format("CREATE TRIGGER CreatedVerticesTrigger ON () CREATE " "{} COMMIT " "EXECUTE " "UNWIND createdVertices as createdVertex " "CREATE (n: {} {{ id: createdVertex.id }})", before_or_after, kTriggerCreatedVertexLabel)); client.DiscardAll(); client.Execute( fmt::format("CREATE TRIGGER CreatedEdgesTrigger ON --> CREATE " "{} COMMIT " "EXECUTE " "UNWIND createdEdges as createdEdge " "CREATE (n: {} {{ id: createdEdge.id }})", before_or_after, kTriggerCreatedEdgeLabel)); client.DiscardAll(); client.Execute( fmt::format("CREATE TRIGGER CreatedObjectsTrigger ON CREATE " "{} COMMIT " "EXECUTE " "UNWIND createdObjects as createdObjectEvent " "WITH CASE createdObjectEvent.event_type WHEN \"created_vertex\" THEN createdObjectEvent.vertex.id " "ELSE createdObjectEvent.edge.id END as id " "CREATE (n: {} {{ id: id }})", before_or_after, kTriggerCreatedObjectLabel)); client.DiscardAll(); } void DropOnCreateTriggers(mg::Client &client) { client.Execute("DROP TRIGGER CreatedVerticesTrigger"); client.DiscardAll(); client.Execute("DROP TRIGGER CreatedEdgesTrigger"); client.DiscardAll(); client.Execute("DROP TRIGGER CreatedObjectsTrigger"); client.DiscardAll(); } int main(int argc, char **argv) { gflags::SetUsageMessage("Memgraph E2E ON CREATE Triggers"); gflags::ParseCommandLineFlags(&argc, &argv, true); memgraph::logging::RedirectToStderr(); mg::Client::Init(); auto client = Connect(); const auto run_create_trigger_tests = [&](bool is_before) { const std::array vertex_ids{1, 2}; const int edge_id = 3; { CreateOnCreateTriggers(*client, is_before); client->BeginTransaction(); for (const auto vertex_id : vertex_ids) { CreateVertex(*client, vertex_id); CheckVertexExists(*client, kVertexLabel, vertex_id); CheckVertexMissing(*client, kTriggerCreatedVertexLabel, vertex_id); CheckVertexMissing(*client, kTriggerCreatedObjectLabel, vertex_id); } CreateEdge(*client, vertex_ids[0], vertex_ids[1], edge_id); CheckVertexMissing(*client, kTriggerCreatedEdgeLabel, edge_id); CheckVertexMissing(*client, kTriggerCreatedObjectLabel, edge_id); client->CommitTransaction(); // :VERTEX x 2 // :CREATED_VERTEX x 2 // :CREATED_EDGE x 1 // :CREATED_OBJECT x 3 static constexpr auto kNumberOfExpectedVertices = 8; if (is_before) { CheckNumberOfAllVertices(*client, kNumberOfExpectedVertices); } else { WaitForNumberOfAllVertices(*client, kNumberOfExpectedVertices); } for (const auto vertex_id : vertex_ids) { CheckVertexExists(*client, kTriggerCreatedVertexLabel, vertex_id); CheckVertexExists(*client, kTriggerCreatedObjectLabel, vertex_id); } CheckVertexExists(*client, kTriggerCreatedEdgeLabel, edge_id); CheckVertexExists(*client, kTriggerCreatedObjectLabel, edge_id); DropOnCreateTriggers(*client); client->Execute("MATCH (n) DETACH DELETE n;"); client->DiscardAll(); } }; static constexpr bool kBeforeCommit = true; static constexpr bool kAfterCommit = false; run_create_trigger_tests(kBeforeCommit); run_create_trigger_tests(kAfterCommit); const auto run_create_trigger_write_proc_create_vertex_test = [&]() { CreateOnCreateTriggers(*client, true); ExecuteCreateVertex(*client, 1); static constexpr auto kNumberOfExpectedVertices = 3; CheckNumberOfAllVertices(*client, kNumberOfExpectedVertices); CheckVertexExists(*client, kTriggerCreatedVertexLabel, 1); CheckVertexExists(*client, kTriggerCreatedObjectLabel, 1); DropOnCreateTriggers(*client); client->Execute("MATCH (n) DETACH DELETE n;"); client->DiscardAll(); }; run_create_trigger_write_proc_create_vertex_test(); const auto run_create_trigger_write_proc_create_edge_test = [&]() { ExecuteCreateVertex(*client, 1); ExecuteCreateVertex(*client, 2); CreateOnCreateTriggers(*client, true); client->Execute("MATCH (n {id:1}), (m {id:2}) CALL write.create_edge(n, m, 'edge') YIELD e RETURN e"); client->DiscardAll(); static constexpr auto kNumberOfExpectedVertices = 4; CheckNumberOfAllVertices(*client, kNumberOfExpectedVertices); CheckVertexExists(*client, kTriggerCreatedEdgeLabel, 1); CheckVertexExists(*client, kTriggerCreatedObjectLabel, 1); DropOnCreateTriggers(*client); client->Execute("MATCH (n) DETACH DELETE n;"); client->DiscardAll(); }; run_create_trigger_write_proc_create_edge_test(); return 0; }